Compare commits

...
67 Commits
Author SHA1 Message Date
Wilson Snyder 0e1fcd38bb Version bump 2013-11-26 19:52:19 -05:00
Wilson Snyder e74186565d Add --compiler clang to work around compiler bug, bug694. 2013-11-26 18:46:55 -05:00
Wilson Snyder 7e54281e26 Fix array assignment from const var, bug693. 2013-10-31 22:39:26 -04:00
Wilson Snyder 15f512bdee Debug: With --debug, run check tree at all steps even if no --dump-more 2013-10-30 23:25:54 -04:00
Wilson Snyder ecfe0283e2 Fix crash with coverage of structures, bug691. 2013-10-29 20:15:01 -04:00
Wilson Snyder 3b874f759c Fix of last commit, bug689. 2013-10-28 21:57:52 -04:00
Wilson Snyder 9c9b4ed4e0 Fix vpi_remove_cb inside callback, bug689. 2013-10-28 21:00:40 -04:00
Wilson Snyder 4f6d80c602 Add UNPACKED warning to convert unpacked structs. 2013-10-28 20:41:05 -04:00
Wilson Snyder b50542531d Fix enum value extension of '1. 2013-10-28 20:24:31 -04:00
Wilson Snyder 8ab28d1d12 Merge branch 'master' of ssh://git-verilator-wsnyder/git/verilator 2013-10-28 11:15:33 -04:00
Wilson Snyder 9567da22f8 Compiler warning fix. 2013-10-28 11:14:13 -04:00
Wilson Snyder 36814b7681 Support vpi_get_time, bug688. 2013-10-22 22:02:53 -04:00
Wilson Snyder 82235e6c6f Fix vpi_get of vpiSuppressVal, bug687. 2013-10-22 22:01:19 -04:00
Wilson Snyder a8310f35f2 Fix evaluation of chained parameter functions, bug684. 2013-10-18 07:06:32 -04:00
Rich Porter 85989af031 Fix vpi_get of vpiSize, bug680.
Signed-off-by: Wilson Snyder <[email protected]>
2013-10-13 20:05:57 -04:00
Rich Porter cf9ffd16dd tests: For icarus, exit on stop. Merge from RPORTER/vpi-vpiSize-680.
Signed-off-by: Wilson Snyder <[email protected]>
2013-10-11 21:34:48 -04:00
Wilson Snyder 0602537cce Fix t/t_select_index2 test. 2013-10-11 21:29:54 -04:00
Wilson Snyder 24e32420b7 Fix multiple VPI variable callbacks, bug679. 2013-10-03 07:24:50 -04:00
Wilson Snyder 39c494260b devel release 2013-09-30 16:56:52 -04:00
Wilson Snyder 761b9c9290 Version bump 2013-09-30 16:53:45 -04:00
Wilson Snyder 27686d8c2f Add --no-order-clock-delay to work around bug613. 2013-09-30 16:52:43 -04:00
Wilson Snyder d2b007005d devel release 2013-09-29 20:56:19 -04:00
Wilson Snyder f1ef30a5bb Version bump 2013-09-29 20:52:29 -04:00
Wilson Snyder f1d9437c55 Report SELRANGE warning for non-generate if, bug675. 2013-09-10 07:16:13 -04:00
Wilson Snyder bcba5075e8 Fix ordering of , msg1229. 2013-09-07 16:43:43 -04:00
Wilson Snyder d6e8b0263c Fix crash on 32-bit Ubuntu, bug670. 2013-09-03 21:40:43 -04:00
Wilson Snyder 9aba617bad Fix --output-split-cfunc to count internal functions. 2013-09-03 19:35:32 -04:00
Wilson Snyder c24f7b1391 Support named function and task arguments. 2013-08-17 20:34:49 -04:00
Wilson Snyder d4e27b635f devel release 2013-08-15 08:43:37 -04:00
Wilson Snyder c996d2870c Version bump 2013-08-15 08:39:46 -04:00
Wilson Snyder bbd59f8a22 Support passing strings to DPI imports. 2013-08-14 21:37:13 -04:00
Wilson Snyder d3d359e757 Fix clang warnings, bug668. 2013-08-08 19:39:39 -04:00
Wilson Snyder ae763ea93d Internals: Debugs for bug666. 2013-08-08 07:05:21 -04:00
Wilson Snyder 236b9e9761 Fix parameter real conversion from integer. 2013-07-29 22:03:47 -04:00
Wilson Snyder e42c9dfd84 Grammar 2013-07-29 21:53:43 -04:00
Wilson Snyder bebf5b291b Fix final duplicate declarations when non-inlined, bug661. 2013-07-29 21:47:23 -04:00
Wilson Snyder 1e3dcd203d Fix clang warning, bug668. 2013-07-29 10:37:58 -04:00
Wilson Snyder cc7da63dec Tests: Add t_mod_recurse. 2013-06-23 22:39:08 -04:00
Wilson Snyder 1baa2a2558 Fix interface ports with comma lists, msg1058. 2013-06-13 19:38:18 -04:00
Wilson Snyder e63ff77b15 VPI internals: Rename VerilatedRange left/right to match IEEE + VNumRange. No functional change. 2013-06-13 08:05:38 -04:00
Wilson Snyder 6cf9468477 Fix vpi_iterate on memory words, bug655. 2013-06-13 07:58:52 -04:00
Jeremy Bennett b277bc8750 Fix ordering of clock enables with delayed assigns, bug613.
Signed-off-by: Wilson Snyder <[email protected]>
2013-06-05 23:35:47 -04:00
Wilson Snyder ba9da64207 Fix t_trace_cat test, bug654. 2013-06-03 19:08:15 -04:00
Wilson Snyder 9cb9f9c80b devel release 2013-06-02 14:52:19 -04:00
Wilson Snyder 7a65df7636 Version bump 2013-06-02 14:47:36 -04:00
Wilson Snyder eab46d547d Version bump. 2013-06-02 14:38:53 -04:00
Wilson Snyder 3dd552c4a2 Duplicate clock gate optimization on by default, use -Od to disable 2013-05-27 22:39:59 -04:00
Wilson Snyder 23bb045a72 Support interfaces and modports, bug102. 2013-05-27 21:39:19 -04:00
Wilson Snyder 7c834ad118 Internals: Misc cleanups from interface branch. No functional change. 2013-05-27 20:56:20 -04:00
Wilson Snyder 8e2617ab8d Internals: V3Inline support for future hard-no-inline. No functional change. 2013-05-26 11:17:42 -04:00
Wilson Snyder 24fcae4f49 Internals: When broken link fatal, say which rule violated 2013-05-25 17:05:22 -04:00
Wilson Snyder ce18674d88 Internals: (see last) also dump on first non-fatal 2013-05-25 13:31:17 -04:00
Wilson Snyder 6b8d9b5c36 Internals: If registered, dump symtable on any error 2013-05-25 12:15:38 -04:00
Wilson Snyder 81bf95763c Internals: Refactor V3Inline to simplify if(m_cellp) out. No functional change. 2013-05-25 10:42:44 -04:00
Wilson Snyder 2d64077fd0 Internals: Prep to allow future move of wrapping. No functional change. 2013-05-25 10:15:10 -04:00
Wilson Snyder 38faebcf20 Fix packed array select internal error, bug652. 2013-05-24 21:32:54 -04:00
Wilson Snyder 48d177a9d0 Fix packed array select internal error, bug652. 2013-05-24 21:14:42 -04:00
Wilson Snyder 3b3a7f7354 Commentary 2013-05-24 19:09:41 -04:00
Wilson Snyder 99cd2818a1 Tests: Allow driver to find 't' signals when not first in file. 2013-05-23 22:00:55 -04:00
Wilson Snyder 5765e099a6 Debug: More digits for debug file sorting. 2013-05-23 20:50:48 -04:00
Wilson Snyder 175d59ecba Fix GCC version runtime changes, bug651. 2013-05-23 20:19:51 -04:00
Wilson Snyder 3bd3d01968 Tests: Move driver.pl tee into perl to avoid process issue, bug650. 2013-05-23 20:08:39 -04:00
Wilson Snyder 85e2a6bb45 Tests 2013-05-21 22:38:35 -04:00
Wilson Snyder 84efd239a5 Fix arrayed input compile error, bug645. Try 2. 2013-05-18 20:17:17 -04:00
Wilson Snyder 6a69813326 Internals: Renames for interfaces. No functional change. 2013-05-18 19:45:52 -04:00
Wilson Snyder 2c9dcc3913 Fix arrayed input compile error, bug645. 2013-05-15 22:00:28 -04:00
Wilson Snyder 20ea1ca018 devel release 2013-05-11 16:16:22 -04:00
160 changed files with 5617 additions and 994 deletions
+71
View File
@@ -3,6 +3,77 @@ 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.854 2013-11-26
*** Add UNPACKED warning to convert unpacked structs. [Jeremy Bennett]
*** Add --compiler clang to work around compiler bug, bug694. [Stefan Ludwig]
**** Support vpi_get of vpiSuppressVal, bug687. [Varun Koyyalagunta]
**** Support vpi_get_time, bug688. [Varun Koyyalagunta]
**** Fix evaluation of chained parameter functions, bug684. [Ted Campbell]
**** Fix enum value extension of '1.
**** Fix multiple VPI variable callbacks, bug679. [Rich Porter]
**** Fix vpi_get of vpiSize, bug680. [Rich Porter]
**** Fix vpi_remove_cb inside callback, bug689. [Varun Koyyalagunta]
**** Fix crash with coverage of structures, bug691. [Eivind Liland]
**** Fix array assignment from const var, bug693. [Jie Xu]
* Verilator 3.853 2013-09-30
**** Add --no-order-clock-delay to work around bug613. [Charlie Brej]
* Verilator 3.852 2013-09-29
*** Support named function and task arguments. [Chris Randall]
*** Report SELRANGE warning for non-generate if, bug675. [Roland Kruse]
**** Fix ordering of $fgetc, msg1229. [Frederic Requin]
**** Fix --output-split-cfunc to count internal functions. [Chris Randall]
**** Fix crash on 32-bit Ubuntu, bug670. [Mark Jackson Pulver]
* Verilator 3.851 2013-08-15
*** Fix ordering of clock enables with delayed assigns, bug613. [Jeremy Bennett]
*** Fix vpi_iterate on memory words, bug655. [Rich Porter]
**** Fix final duplicate declarations when non-inlined, bug661. [Charlie Brej]
**** Fix interface ports with comma lists, msg1058. [Ed Lander]
**** Fix parameter real conversion from integer.
**** Fix clang warnings, bug668. [Yutetsu Takatsukasa]
* Verilator 3.850 2013-06-02
** Support interfaces and modports, bug102. [Byron Bradley, Jeremy Bennett]
*** Duplicate clock gate optimization on by default, bug621.
**** Fix arrayed input compile error, bug645. [Krzysztof Jankowski]
**** Fix GCC version runtime changes, bug651. [Jeremy Bennett]
**** Fix packed array select internal error, bug652. [Krzysztof Jankowski]
* Verilator 3.847 2013-05-11
*** Add ALWCOMBORDER warning. [KC Buckenmaier]
+36 -8
View File
@@ -299,8 +299,10 @@ descriptions in the next sections for more information.
-O3 High performance optimizations
-O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable
--no-order-clock-delay Disable ordering clock enable assignments
--output-split <bytes> Split .cpp files into pieces
--output-split-cfuncs <statements> Split .ccp functions
--output-split-cfuncs <statements> Split .cpp functions
--output-split-ctrace <statements> Split tracing 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
@@ -467,6 +469,12 @@ Enables tunings and work-arounds for the specified C++ compiler.
=over 4
=item clang
Tune for clang. This may reduce execution speed as it enables several
workarounds to avoid silly hardcoded limits in clang. This includes
breaking deep structures as for msvc as described below.
=item gcc
Tune for Gnu C++, although generated code should work on almost any
@@ -788,6 +796,12 @@ mappings of optimizations to -O letters.
Specify the name for the final executable built if using --exe. Defaults
to the --prefix if not specified.
=item --no-order-clock-delay
Rarely needed. Disables a bug fix for ordering of clock enables with
delayed assignments. This flag should only be used when suggested by the
developers.
=item --output-split I<bytes>
Enables splitting the output .cpp/.sp files into multiple outputs. When a
@@ -810,6 +824,11 @@ worse with decreasing split values. Note that this option is stronger than
--output-split in the sense that --output-split will not split inside a
function.
=item --output-split-ctrace I<statements>
Enables splitting trace functions in the output .cpp/.sp files into
multiple functions. Defaults to same setting as --output-split-cfuncs.
=item --pins64
Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
@@ -1920,16 +1939,12 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
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.
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
const, do-while, enum, export, final, import, int, logic, longint, package,
program, shortint, struct, time, typedef, union, var, void, priority
case/if, and unique case/if.
const, do-while, enum, export, final, import, int, interface, logic,
longint, modport, package, program, shortint, struct, time, typedef, union,
var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
@@ -2605,6 +2620,12 @@ and continue keywords.
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
=item interface
Interfaces and modports, including with generated data types are supported.
Generate blocks around modports are not supported, nor are virtual
interfaces nor unnamed interfaces.
=item priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted to be
@@ -3210,6 +3231,13 @@ section for more details.
Ignoring this warning will only slow simulations, it will simulate
correctly.
=item UNPACKED
Warns that unpacked structs and unions are not supported.
Ignoring this warning will make Verilator treat the structure as packed,
which may make Verilator simulations differ from other simulators.
=item UNSIGNED
Warns that you are comparing a unsigned value in a way that implies it is
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.847 2013-05-11])
AC_INIT([Verilator],[3.854 2013-11-26])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
+14 -5
View File
@@ -769,6 +769,15 @@ void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, destp, (int)output.length(), output.c_str());
}
void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...) {
if (obits_ignored) {}
output = "";
va_list ap;
va_start(ap,formatp);
_vl_vsformat(output, formatp, ap);
va_end(ap);
}
string VL_SFORMATF_NX(const char* formatp, ...) {
VL_STATIC_OR_THREAD string output; // static only for speed
output = "";
@@ -1114,7 +1123,7 @@ vluint32_t VerilatedVar::entSize() const {
case VLVT_UINT16: size=sizeof(SData); break;
case VLVT_UINT32: size=sizeof(IData); break;
case VLVT_UINT64: size=sizeof(QData); break;
case VLVT_WDATA: size=VL_WORDS_I(range().bits())*sizeof(IData); break;
case VLVT_WDATA: size=VL_WORDS_I(range().elements())*sizeof(IData); break;
default: size=0; break;
}
return size;
@@ -1186,11 +1195,11 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
int msb = va_arg(ap,int);
int lsb = va_arg(ap,int);
if (i==0) {
var.m_range.m_lhs = msb;
var.m_range.m_rhs = lsb;
var.m_range.m_left = msb;
var.m_range.m_right = lsb;
} else if (i==1) {
var.m_array.m_lhs = msb;
var.m_array.m_rhs = lsb;
var.m_array.m_left = msb;
var.m_array.m_right = lsb;
} else {
// We could have a linked list of ranges, but really this whole thing needs
// to be generalized to support structs and unions, etc.
+3 -4
View File
@@ -145,7 +145,7 @@ public:
# define VL_CELL(instname,type) ///< Declare a cell, ala SP_CELL
/// Declare a module, ala SC_MODULE
# define VL_MODULE(modname) struct modname : public VerilatedModule
# define VL_MODULE(modname) class modname : public VerilatedModule
/// Constructor, ala SC_CTOR
# define VL_CTOR(modname) modname(const char* __VCname="")
@@ -216,9 +216,8 @@ public: // But internals only - called from VerilatedModule's
//===========================================================================
/// Verilator global static information class
struct Verilated {
class Verilated {
// MEMBERS
private:
// Slow path variables
static VerilatedVoidCb s_flushCb; ///< Flush callback function
@@ -871,7 +870,7 @@ static inline WDataOutP VL_OR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP r
}
// EMIT_RULE: VL_CHANGEXOR: oclean=1; obits=32; lbits==rbits;
static inline IData VL_CHANGEXOR_W(int words, WDataInP lwp,WDataInP rwp){
IData od;
IData od = 0;
for (int i=0; (i < words); i++) od |= (lwp[i] ^ rwp[i]);
return(od);
}
+4
View File
@@ -41,11 +41,15 @@ inline string VL_CVT_PACK_STR_NQ(QData lhs) {
IData lw[2]; VL_SET_WQ(lw, lhs);
return VL_CVT_PACK_STR_NW(2, lw);
}
inline string VL_CVT_PACK_STR_NQ(string lhs) {
return lhs;
}
inline string VL_CVT_PACK_STR_NI(IData lhs) {
IData lw[1]; lw[0] = lhs;
return VL_CVT_PACK_STR_NW(1, lw);
}
extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
extern string VL_SFORMATF_NX(const char* formatp, ...);
#endif // Guard
+10 -8
View File
@@ -45,19 +45,20 @@ struct VerilatedCStrCmp {
//===========================================================================
/// Verilator range
// See also V3Ast::VNumRange
class VerilatedRange {
int m_lhs;
int m_rhs;
int m_left;
int m_right;
protected:
friend class VerilatedVar;
friend class VerilatedScope;
VerilatedRange() : m_lhs(0), m_rhs(0) {}
void sets(int lhs, int rhs) { m_lhs=lhs; m_rhs=rhs; }
VerilatedRange() : m_left(0), m_right(0) {}
void sets(int left, int right) { m_left=left; m_right=right; }
public:
~VerilatedRange() {}
int lhs() const { return m_lhs; }
int rhs() const { return m_rhs; }
int bits() const { return (VL_LIKELY(m_lhs>=m_rhs)?(m_lhs-m_rhs+1):(m_rhs-m_lhs+1)); }
int left() const { return m_left; }
int right() const { return m_right; }
int elements() const { return (VL_LIKELY(m_left>=m_right)?(m_left-m_right+1):(m_right-m_left+1)); }
};
//===========================================================================
@@ -92,7 +93,8 @@ public:
//======================================================================
/// Types
struct VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
class VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
public:
VerilatedVarNameMap() {}
~VerilatedVarNameMap() {}
};
+176 -71
View File
@@ -38,7 +38,7 @@
// Internal macros
#define _VL_VPI_INTERNAL VerilatedVpi::error_info()->setMessage(vpiInternal)->setMessage
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
#define _VL_VPI_ERROR VerilatedVpi::error_info()->setMessage(vpiError )->setMessage
#define _VL_VPI_WARNING VerilatedVpi::error_info()->setMessage(vpiWarning )->setMessage
#define _VL_VPI_NOTICE VerilatedVpi::error_info()->setMessage(vpiNotice )->setMessage
@@ -52,6 +52,8 @@
// Implementation
#include <set>
#include <list>
#include <map>
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
#define VL_VPI_LINE_SIZE 8192
@@ -94,6 +96,9 @@ public:
virtual const char* name() { return "<null>"; }
virtual const char* fullname() { return "<null>"; }
virtual const char* defname() { return "<null>"; }
virtual const vluint32_t type() { return 0; }
virtual const vluint32_t size() { return 0; }
virtual const VerilatedRange* rangep() { return 0; }
virtual vpiHandle dovpi_scan() { return 0; }
};
@@ -112,6 +117,7 @@ public:
}
virtual ~VerilatedVpioCb() {}
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiCallback; }
vluint32_t reason() const { return m_cbData.reason; }
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
t_cb_data* cb_datap() { return &(m_cbData); }
@@ -124,19 +130,20 @@ public:
VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
virtual ~VerilatedVpioConst() {}
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiUndefined; }
vlsint32_t num() const { return m_num; }
};
class VerilatedVpioRange : public VerilatedVpio {
vlsint32_t m_lhs; // Ranges can be signed
vlsint32_t m_rhs;
const VerilatedRange* m_range;
bool m_iteration;
public:
VerilatedVpioRange(vlsint32_t lhs, vlsint32_t rhs) : m_lhs(lhs), m_rhs(rhs), m_iteration(0) {}
VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
virtual ~VerilatedVpioRange() {}
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
vlsint32_t lhs() const { return m_lhs; }
vlsint32_t rhs() const { return m_rhs; }
virtual const vluint32_t type() { return vpiRange; }
virtual const vluint32_t size() const { return m_range->elements(); }
virtual const VerilatedRange* rangep() const { return m_range; }
int iteration() const { return m_iteration; }
void iterationInc() { ++m_iteration; }
virtual vpiHandle dovpi_scan() {
@@ -157,6 +164,7 @@ public:
: m_scopep(scopep) {}
virtual ~VerilatedVpioScope() {}
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiScope; }
const VerilatedScope* scopep() const { return m_scopep; }
virtual const char* name() { return m_scopep->name(); }
virtual const char* fullname() { return m_scopep->name(); }
@@ -174,11 +182,15 @@ class VerilatedVpioVar : public VerilatedVpio {
protected:
void* m_varDatap; // varp()->datap() adjusted for array entries
vlsint32_t m_index;
const VerilatedRange& get_range() {
// Determine number of dimensions and return outermost
return (m_varp->dims()>1) ? m_varp->array() : m_varp->range();
}
public:
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
: m_varp(varp), m_scopep(scopep), m_index(0) {
m_prevDatap = NULL;
m_mask.u32 = VL_MASK_I(varp->range().bits());
m_mask.u32 = VL_MASK_I(varp->range().elements());
m_entSize = varp->entSize();
m_varDatap = varp->datap();
}
@@ -191,6 +203,13 @@ public:
vluint32_t mask() const { return m_mask.u32; }
vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; }
vluint32_t entSize() const { return m_entSize; }
const vluint32_t index() { return m_index; }
virtual const vluint32_t type() {
if (varp()->vldir() != vpiNoDirection) return vpiPort;
return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */
}
virtual const vluint32_t size() { return get_range().elements(); }
virtual const VerilatedRange* rangep() { return &get_range(); }
virtual const char* name() { return m_varp->name(); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
@@ -207,16 +226,19 @@ public:
}
};
class VerilatedVpioVarIndex : public VerilatedVpioVar {
class VerilatedVpioMemoryWord : public VerilatedVpioVar {
public:
VerilatedVpioVarIndex(const VerilatedVar* varp, const VerilatedScope* scopep,
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
vlsint32_t index, int offset)
: VerilatedVpioVar(varp, scopep) {
m_index = index;
m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset;
}
virtual ~VerilatedVpioVarIndex() {}
static inline VerilatedVpioVarIndex* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIndex*>((VerilatedVpio*)h); }
virtual ~VerilatedVpioMemoryWord() {}
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiMemoryWord; }
virtual const vluint32_t size() { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() { return &(varp()->range()); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
char num[20]; sprintf(num,"%d",m_index);
@@ -234,6 +256,7 @@ public:
: m_scopep(scopep), m_started(false) { }
virtual ~VerilatedVpioVarIter() {}
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiIterator; }
virtual vpiHandle dovpi_scan() {
if (VL_LIKELY(m_scopep->varsp())) {
if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; }
@@ -248,6 +271,28 @@ public:
}
};
class VerilatedVpioMemoryWordIter : public VerilatedVpio {
const vpiHandle m_handle;
const VerilatedVar* m_varp;
vlsint32_t m_iteration;
vlsint32_t m_direction;
bool m_done;
public:
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
: m_handle(handle), m_varp(varp), m_iteration(varp->array().right()), m_direction(VL_LIKELY(varp->array().left()>varp->array().right())?1:-1), m_done(false) { }
virtual ~VerilatedVpioMemoryWordIter() {}
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiIterator; }
void iterationInc() { if (!(m_done = m_iteration == m_varp->array().left())) m_iteration+=m_direction; }
virtual vpiHandle dovpi_scan() {
vpiHandle result;
if (m_done) return 0;
result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
}
};
//======================================================================
struct VerilatedVpiTimedCbsCmp {
@@ -260,14 +305,19 @@ struct VerilatedVpiTimedCbsCmp {
}
};
struct VerilatedVpiError;
class VerilatedVpiError;
class VerilatedVpi {
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason
typedef set<VerilatedVpioCb*> VpioCbSet;
typedef list<VerilatedVpioCb*> VpioCbList;
typedef set<pair<QData,VerilatedVpioCb*>,VerilatedVpiTimedCbsCmp > VpioTimedCbs;
VpioCbSet m_cbObjSets[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
struct product_info {
PLI_BYTE8* product;
PLI_BYTE8* version;
};
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
VpioTimedCbs m_timedCbs; // Time based callbacks
VerilatedVpiError* m_errorInfop; // Container for vpi error info
@@ -283,16 +333,17 @@ public:
}
}
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) vl_fatal(__FILE__,__LINE__,"", "vpi bb reason too large");
s_s.m_cbObjSets[vop->reason()].insert(vop);
s_s.m_cbObjLists[vop->reason()].push_back(vop);
}
static void cbTimedAdd(VerilatedVpioCb* vop) {
s_s.m_timedCbs.insert(make_pair(vop->time(), vop));
}
static void cbReasonRemove(VerilatedVpioCb* cbp) {
VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbp->reason()];
VpioCbSet::iterator it=cbObjSet.find(cbp);
if (VL_LIKELY(it != cbObjSet.end())) {
cbObjSet.erase(it);
VpioCbList& cbObjList = s_s.m_cbObjLists[cbp->reason()];
// We do not remove it now as we may be iterating the list,
// instead set to NULL and will cleanup later
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end(); ++it) {
if (*it == cbp) *it = NULL;
}
}
static void cbTimedRemove(VerilatedVpioCb* cbp) {
@@ -322,19 +373,26 @@ public:
}
}
static void callCbs(vluint32_t reason) {
VpioCbSet& cbObjSet = s_s.m_cbObjSets[reason];
for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) {
VerilatedVpioCb* vop = *it;
++it; // iterator may be deleted by callback
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
}
VerilatedVpioCb* vop = *it++;
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: reason_callback %d %p\n",reason,vop););
(vop->cb_rtnp()) (vop->cb_datap());
}
}
static void callValueCbs() {
VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbValueChange];
for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) {
VerilatedVpioCb* vop = *it;
++it; // iterator may be deleted by callback
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
set<VerilatedVpioVar*> update; // set of objects to update after callbacks
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
}
VerilatedVpioCb* vop = *it++;
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
void* newDatap = varop->varDatap();
void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback
@@ -344,12 +402,15 @@ public:
if (memcmp(prevDatap, newDatap, varop->entSize())) {
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n",
vop,varop->fullname(), *((CData*)newDatap)););
memcpy(prevDatap, newDatap, varop->entSize());
update.insert(varop);
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
(vop->cb_rtnp()) (vop->cb_datap());
}
}
}
for (set<VerilatedVpioVar*>::iterator it=update.begin(); it!=update.end(); it++ ) {
memcpy((*it)->prevDatap(), (*it)->varDatap(), (*it)->entSize());
}
}
static VerilatedVpiError* error_info(); // getter for vpi error info
@@ -545,15 +606,15 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
_VL_VPI_ERROR_RESET(); // reset vpi error status
if (VL_LIKELY(varop)) {
if (varop->varp()->dims()<2) return 0;
if (VL_LIKELY(varop->varp()->array().lhs() >= varop->varp()->array().rhs())) {
if (VL_UNLIKELY(indx > varop->varp()->array().lhs() || indx < varop->varp()->array().rhs())) return 0;
return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->array().rhs()))
if (VL_LIKELY(varop->varp()->array().left() >= varop->varp()->array().right())) {
if (VL_UNLIKELY(indx > varop->varp()->array().left() || indx < varop->varp()->array().right())) return 0;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->array().right()))
->castVpiHandle();
} else {
if (VL_UNLIKELY(indx < varop->varp()->array().lhs() || indx > varop->varp()->array().rhs())) return 0;
return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->array().lhs()))
if (VL_UNLIKELY(indx < varop->varp()->array().left() || indx > varop->varp()->array().right())) return 0;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->array().left()))
->castVpiHandle();
}
} else {
@@ -568,21 +629,32 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle %d %p\n",type,object););
_VL_VPI_ERROR_RESET(); // reset vpi error status
switch (type) {
case vpiLeftRange: // FALLTHRU
case vpiLeftRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
case vpiRightRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
vluint32_t num = ((type==vpiLeftRange)
? vop->varp()->range().lhs()
: vop->varp()->range().rhs());
return (new VerilatedVpioConst(num))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
vluint32_t num = ((type==vpiLeftRange)
? vop->lhs()
: vop->rhs());
return (new VerilatedVpioConst(num))->castVpiHandle();
} else {
return 0;
}
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
@@ -600,13 +672,25 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
_VL_VPI_ERROR_RESET(); // reset vpi error status
switch (type) {
case vpiMemoryWord: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims());
}
return (new VerilatedVpioMemoryWordIter(object, vop->varp()))->castVpiHandle();
}
case vpiRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
// Unsupported is multidim list
return ((new VerilatedVpioRange(vop->varp()->array().lhs(),
vop->varp()->array().rhs()))
->castVpiHandle());
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type), vop->fullname() , vop->varp()->dims());
}
return ((new VerilatedVpioRange(vop->rangep()))->castVpiHandle());
}
case vpiReg: {
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
@@ -639,9 +723,9 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
return VL_TIME_PRECISION;
}
case vpiType: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
VerilatedVpio* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return ((vop->varp()->dims()>1) ? vpiMemory : vpiReg);
return vop->type();
}
case vpiDirection: {
// By forthought, the directions already are vpi enumerated
@@ -649,11 +733,16 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
if (VL_UNLIKELY(!vop)) return 0;
return vop->varp()->vldir();
}
case vpiScalar: // FALLTHRU
case vpiVector: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims()==0) return 0;
else return 1;
return (property==vpiVector)^(vop->varp()->dims()==0);
}
case vpiSize: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
return vop->size();
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
@@ -730,7 +819,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
out[0].bval = 0;
return;
case VLVT_WDATA: {
int words = VL_WORDS_I(vop->varp()->range().bits());
int words = VL_WORDS_I(vop->varp()->range().elements());
if (VL_UNLIKELY(words >= VL_MULS_MAX_WORDS)) {
vl_fatal(__FILE__,__LINE__,"", "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
}
@@ -763,7 +852,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int bits = vop->varp()->range().bits();
int bits = vop->varp()->range().elements();
CData* datap = ((CData*)(vop->varDatap()));
int i;
if (bits > outStrSz) {
@@ -792,8 +881,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int chars = (vop->varp()->range().bits()+2)/3;
int bytes = VL_BYTES_I(vop->varp()->range().bits());
int chars = (vop->varp()->range().elements()+2)/3;
int bytes = VL_BYTES_I(vop->varp()->range().elements());
CData* datap = ((CData*)(vop->varDatap()));
int i;
if (chars > outStrSz) {
@@ -815,7 +904,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
if (i==(chars-1)) {
// most signifcant char, mask off non existant bits when vector
// size is not a multiple of 3
unsigned int rem = vop->varp()->range().bits() % 3;
unsigned int rem = vop->varp()->range().elements() % 3;
if (rem) {
// generate bit mask & zero non existant bits
val &= (1<<rem)-1;
@@ -854,7 +943,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int chars = (vop->varp()->range().bits()+3)>>2;
int chars = (vop->varp()->range().elements()+3)>>2;
CData* datap = ((CData*)(vop->varDatap()));
int i;
if (chars > outStrSz) {
@@ -869,7 +958,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
if (i==(chars-1)) {
// most signifcant char, mask off non existant bits when vector
// size is not a multiple of 4
unsigned int rem = vop->varp()->range().bits() & 3;
unsigned int rem = vop->varp()->range().elements() & 3;
if (rem) {
// generate bit mask & zero non existant bits
val &= (1<<rem)-1;
@@ -893,7 +982,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int bytes = VL_BYTES_I(vop->varp()->range().bits());
int bytes = VL_BYTES_I(vop->varp()->range().elements());
CData* datap = ((CData*)(vop->varDatap()));
int i;
if (bytes > outStrSz) {
@@ -936,6 +1025,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
return;
}
} else if (value_p->format == vpiSuppressVal) {
return;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
@@ -984,7 +1075,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
*((IData*)(vop->varDatap())) = value_p->value.vector[0].aval & vop->mask();
return object;
case VLVT_WDATA: {
int words = VL_WORDS_I(vop->varp()->range().bits());
int words = VL_WORDS_I(vop->varp()->range().elements());
WDataOutP datap = ((IData*)(vop->varDatap()));
for (int i=0; i<words; i++) {
datap[i] = value_p->value.vector[i].aval;
@@ -1013,7 +1104,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int bits = vop->varp()->range().bits();
int bits = vop->varp()->range().elements();
int len = strlen(value_p->value.str);
CData* datap = ((CData*)(vop->varDatap()));
for (int i=0; i<bits; i++) {
@@ -1040,8 +1131,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int chars = (vop->varp()->range().bits()+2)/3;
int bytes = VL_BYTES_I(vop->varp()->range().bits());
int chars = (vop->varp()->range().elements()+2)/3;
int bytes = VL_BYTES_I(vop->varp()->range().elements());
int len = strlen(value_p->value.str);
CData* datap = ((CData*)(vop->varDatap()));
div_t idx;
@@ -1126,7 +1217,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int chars = (vop->varp()->range().bits()+3)>>2;
int chars = (vop->varp()->range().elements()+3)>>2;
CData* datap = ((CData*)(vop->varDatap()));
char* val = value_p->value.str;
// skip hex ident if one is detected at the start of the string
@@ -1173,7 +1264,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: {
int bytes = VL_BYTES_I(vop->varp()->range().bits());
int bytes = VL_BYTES_I(vop->varp()->range().elements());
int len = strlen(value_p->value.str);
CData* datap = ((CData*)(vop->varDatap()));
for (int i=0; i<bytes; i++) {
@@ -1227,7 +1318,21 @@ void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
// time processing
void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
_VL_VPI_UNIMP(); return;
if (VL_UNLIKELY(!time_p)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer");
return;
}
if (time_p->type == vpiSimTime) {
QData qtime = VL_TIME_Q();
IData itime[2];
VL_SET_WQ(itime, qtime);
time_p->low = itime[0];
time_p->high = itime[1];
return;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported type (%d)",
VL_FUNC, time_p->type);
return;
}
// I/O routines
+19 -23
View File
@@ -24,14 +24,14 @@ more details.
=head1 DESCRIPTION
Verilator converts synthesizable (not behavioral) Verilog code into C++ or
SystemC code. It is not a complete simulator, just a translator.
Verilator converts synthesizable (generally not behavioral) Verilog code
into C++ or SystemC code. It is not a complete simulator, just a
translator.
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
reads the specified Verilog code, lints it, and optionally adds coverage
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
it outputs .sp files for the SystemPerl preprocessor available at
http://www.veripool.org.
it outputs .cpp and .h files using the standard SystemC headers.
The resulting files are then compiled with C++. The user writes a little
C++ wrapper file, which instantiates the top level module. This is
@@ -41,14 +41,11 @@ The resulting executable will perform the actual simulation.
=head1 SUPPORTED SYSTEMS
Verilator is developed and has primary testing on:
SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2
Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It
should run with minor porting on any Linix-ish platform. Verilator also
works on Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
Verilated output (not Verilator itself) compiles under MSVC++ 2008.
Verilator is developed and has primary testing on Ubuntu. Versions have
also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
with minor porting on any Linix-ish platform. Verilator also works on
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
output (not Verilator itself) compiles under MSVC++ 2008 and newer.
=head1 INSTALLATION
@@ -71,11 +68,11 @@ Download the latest package from that site, and decompress.
=item
If you will be using SystemC (vs straight C++ output), download SystemC
2.0.1 from L<http://www.systemc.org>. Follow their installation
instructions. You will need to set SYSTEMC_INCLUDE to point to the
include directory with systemc.h in it, and SYSTEMC_LIBDIR to points
to the directory with libsystemc.a in it. (Older installations may
set SYSTEMC and SYSTEMC_ARCH instead.)
from L<http://www.systemc.org>. Follow their installation instructions.
You will need to set SYSTEMC_INCLUDE to point to the include directory with
systemc.h in it, and SYSTEMC_LIBDIR to points to the directory with
libsystemc.a in it. (Older installations may set SYSTEMC and SYSTEMC_ARCH
instead.)
=item
@@ -107,7 +104,7 @@ executable, so try to have them correct before configuring.
Our personal favorite is to always run Verilator from the kit directory.
This allows the easiest experimentation and upgrading. It's also how most
EDA tools operate; to run any of them you point to the tarball.
EDA tools operate; to run you point to the tarball, no install is needed.
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
@@ -156,11 +153,10 @@ PATH.
Type C<make> to compile Verilator.
Type C<make test_c> to check the compilation.
Type C<make test> to check the compilation.
Type C<make test> for a more complete test. You may get a error about the
Bit::Vector Perl package. You will need to install it and SystemPerl if
you want all tests to pass.
Configure with C<--enable-longtests> for more complete developer tests.
Additional packages may be required for these tests.
You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
@@ -195,7 +191,7 @@ The directories in the kit after de-taring are as follows:
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
include/verilated.h => Global headers
include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
+1 -1
View File
@@ -291,7 +291,7 @@ private:
}
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
if (!m_scopeFinalp) {
m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final", m_namer.scopep());
m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(), m_namer.scopep());
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
m_scopeFinalp->dontCombine(true);
+10 -2
View File
@@ -965,6 +965,14 @@ void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only
v3Global.rootp()->dumpTreeFile(filename);
}
void AstNode::checkIter() const {
if (m_iterpp) {
dumpPtrs(cout);
// Perhaps something forgot to clear m_iterpp?
this->v3fatalSrc("Iteration link should be NULL");
}
}
void AstNode::dumpPtrs(ostream& os) const {
os<<"This="<<typeName()<<" "<<(void*)this;
os<<" back="<<(void*)backp();
@@ -1008,8 +1016,8 @@ void AstNode::dumpTreeAndNext(ostream& os, const string& indent, int maxDepth) {
}
}
void AstNode::dumpTreeFile(const string& filename, bool append) {
if (v3Global.opt.dumpTree()) {
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
if (v3Global.opt.dumpTree() && doDump) {
{ // Write log & close
UINFO(2,"Dumping "<<filename<<endl);
const auto_ptr<ofstream> logsp (V3File::new_ofstream(filename, append));
+25 -9
View File
@@ -38,6 +38,9 @@ class VFlagLogicPacked {};
class VFlagBitPacked {};
class VFlagChildDType {}; // Used by parser.y to select constructor that sets childDType
// For broken() function, return error string if have a match
#define BROKEN_RTN(test) do { if (VL_UNLIKELY(test)) return # test; } while(0)
//######################################################################
class AstType {
@@ -407,7 +410,8 @@ public:
BLOCKTEMP,
MODULETEMP,
STMTTEMP,
XTEMP
XTEMP,
IFACEREF // Used to link Interfaces between modules
};
enum en m_e;
inline AstVarType () : m_e(UNKNOWN) {}
@@ -421,7 +425,8 @@ public:
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE",
"TRIWIRE","TRI0","TRI1",
"PORT",
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"};
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP",
"IFACEREF"};
return names[m_e]; }
bool isSignal() const { return (m_e==WIRE || m_e==IMPLICITWIRE
|| m_e==TRIWIRE
@@ -1148,12 +1153,14 @@ public:
bool sameTree(AstNode* node2p); // Does tree of this == node2p?
void deleteTree(); // Always deletes the next link
void checkTree(); // User Interface version
void checkIter() const;
void clearIter() { m_iterpp=NULL; }
void dumpPtrs(ostream& str=cout) const;
void dumpTree(ostream& str=cout, const string& indent=" ", int maxDepth=0);
void dumpTree(const string& indent, int maxDepth=0) { dumpTree(cout,indent,maxDepth); }
void dumpTreeGdb(); // For GDB only
void dumpTreeAndNext(ostream& str=cout, const string& indent=" ", int maxDepth=0);
void dumpTreeFile(const string& filename, bool append=false);
void dumpTreeFile(const string& filename, bool append=false, bool doDump=true);
static void dumpTreeFileGdb(const char* filenamep=NULL);
// METHODS - queries
@@ -1171,7 +1178,7 @@ public:
virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null
virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool broken() const { return false; }
virtual const char* broken() const { return NULL; }
// INVOKERS
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
@@ -1472,7 +1479,7 @@ public:
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual bool hasDType() const { return true; }
virtual bool broken() const;
virtual const char* broken() const;
virtual int instrCount() const { return widthInstrs(); }
virtual void cloneRelink();
virtual string name() const { return m_name; } // * = Var name
@@ -1535,6 +1542,7 @@ public:
virtual bool hasDType() const { return true; }
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs to next non-typeref type
virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs to next non-typeref-or-const type
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
virtual bool maybePointedTo() const { return true; }
@@ -1579,17 +1587,19 @@ public:
numeric(numericUnpack.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
}
ASTNODE_BASE_FUNCS(NodeClassDType)
virtual bool broken() const;
virtual const char* broken() const;
virtual void dump(ostream& str);
// For basicp() we reuse the size to indicate a "fake" basic type of same size
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// op1 = members
AstMemberDType* membersp() const { return op1p()->castMemberDType(); } // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; }
bool packedUnsup() const { return true; } // packed() but as don't support unpacked, presently all structs
void clearCache() { m_members.clear(); }
void repairMemberCache();
AstMemberDType* findMember(const string& name) const {
@@ -1615,8 +1625,8 @@ public:
ASTNODE_BASE_FUNCS(NodeArrayDType)
virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str);
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -1638,6 +1648,7 @@ public:
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const;
@@ -1740,7 +1751,7 @@ public:
addNOp2p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) {
m_taskp = m_taskp->clonep()->castNodeFTask();
}}
@@ -1847,4 +1858,9 @@ inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); }
inline void AstIfaceRefDType::cloneRelink() {
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep()->castCell();
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep()->castIface();
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep()->castModport(); }
#endif // Guard
+46 -11
View File
@@ -35,8 +35,22 @@
// Special methods
// We need these here, because the classes they point to aren't defined when we declare the class
bool AstNodeVarRef::broken() const { return ((m_varScopep && !m_varScopep->brokeExists())
|| (m_varp && !m_varp->brokeExists())); }
const char* AstIfaceRefDType::broken() const {
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
return NULL;
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
return ((m_cellp && m_cellp->modp()) ? m_cellp->modp()->castIface() : m_ifacep);
}
const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return NULL;
}
void AstNodeVarRef::cloneRelink() {
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep()->castVar(); }
@@ -54,18 +68,18 @@ void AstNodeClassDType::repairMemberCache() {
}
}
bool AstNodeClassDType::broken() const {
const char* AstNodeClassDType::broken() const {
set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
if (exists.find(it->second) == exists.end()) {
if (VL_UNLIKELY(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
return true;
return "member broken";
}
}
return false;
return NULL;
}
int AstBasicDType::widthAlignBytes() const {
@@ -419,10 +433,12 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable
return nodep;
}
bool AstScope::broken() const {
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|| !m_modp || !m_modp->brokeExists());
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
BROKEN_RTN(!m_modp);
BROKEN_RTN(m_modp && !m_modp->brokeExists());
return NULL;
}
void AstScope::cloneRelink() {
@@ -718,12 +734,31 @@ void AstEnumItemRef::dump(ostream& str) {
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
void AstIfaceRefDType::dump(ostream& str) {
this->AstNode::dump(str);
if (cellName()!="") { str<<" cell="<<cellName(); }
if (ifaceName()!="") { str<<" if="<<ifaceName(); }
if (modportName()!="") { str<<" mp="<<modportName(); }
if (cellp()) { str<<" -> "; cellp()->dump(str); }
else if (ifacep()) { str<<" -> "; ifacep()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstIfaceRefDType::dumpSmall(ostream& str) {
this->AstNodeDType::dumpSmall(str);
str<<"iface";
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstModportVarRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" "<<varType();
if (varp()) { str<<" -> "; varp()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
@@ -839,7 +874,7 @@ void AstVarXRef::dump(ostream& str) {
if (lvalue()) str<<" [LV] => ";
else str<<" [RV] <- ";
str<<dotted()<<". - ";
if (inlinedDots()!="") str<<" flat.="<<inlinedDots()<<" - ";
if (inlinedDots()!="") str<<" inline.="<<inlinedDots()<<" - ";
if (varScopep()) { varScopep()->dump(str); }
else if (varp()) { varp()->dump(str); }
else { str<<"UNLINKED"; }
+168 -34
View File
@@ -227,6 +227,7 @@ public:
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
virtual string name() const { return m_name; }
@@ -244,16 +245,16 @@ public:
refDTypep(NULL);
setOp2p(rangep);
dtypep(NULL); // V3Width will resolve
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width,width);
}
AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
refDTypep(dtp);
setOp2p(rangep);
dtypep(this);
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width,width);
}
ASTNODE_NODE_FUNCS(PackArrayDType, PACKARRAYDTYPE)
};
@@ -357,7 +358,7 @@ public:
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; }
virtual string name() const { return m.m_keyword.ascii(); }
virtual bool broken() const { return dtypep()!=this; }
virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(VSignedState signst) {
@@ -368,6 +369,7 @@ public:
// METHODS
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead
@@ -410,8 +412,8 @@ public:
widthFromSub(subDTypep());
}
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -427,11 +429,55 @@ public:
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
struct AstIfaceRefDType : public AstNodeDType {
// Reference to an interface, either for a port, or inside parent cell
private:
string m_cellName; // "" = no cell, such as when connects to 'input' iface
string m_ifaceName; // Interface name
string m_modportName; // "" = no modport
AstIface* m_ifacep; // Pointer to interface; note cellp() should override
AstCell* m_cellp; // When exact parent cell known; not a guess
AstModport* m_modportp; // NULL = unlinked or no modport
public:
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(""),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName, const string& modport)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(modport),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
ASTNODE_NODE_FUNCS(IfaceRefDType, IFACEREFDTYPE)
// METHODS
virtual const char* broken() const;
virtual void dump(ostream& str=cout);
virtual void dumpSmall(ostream& str);
virtual void cloneRelink();
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
void cellName(const string& name) { m_cellName=name; }
string ifaceName() const { return m_ifaceName; }
void ifaceName(const string& name) { m_ifaceName=name; }
string modportName() const { return m_modportName; }
void modportName(const string& name) { m_modportName=name; }
AstIface* ifaceViaCellp() const; // Use cellp or ifacep
AstIface* ifacep() const { return m_ifacep; }
void ifacep(AstIface* nodep) { m_ifacep=nodep; }
AstCell* cellp() const { return m_cellp; }
void cellp(AstCell* nodep) { m_cellp=nodep; }
AstModport* modportp() const { return m_modportp; }
void modportp(AstModport* modportp) { m_modportp=modportp; }
bool isModport() { return !m_modportName.empty(); }
};
struct AstRefDType : public AstNodeDType {
private:
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
@@ -447,7 +493,7 @@ public:
}
ASTNODE_NODE_FUNCS(RefDType, REFDTYPE)
// METHODS
virtual bool broken() const { return m_refDTypep && !m_refDTypep->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -464,6 +510,10 @@ public:
if (defp()) return defp()->skipRefp();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual AstNodeDType* skipRefToConstp() const {
if (defp()) return defp()->skipRefToConstp();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) { m_name = flag; }
@@ -531,7 +581,8 @@ public:
//
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
virtual AstNodeDType* skipRefp() const { return dtypeSkipRefp(); }
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// METHODS
@@ -571,7 +622,7 @@ public:
ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF)
virtual void dump(ostream& str);
virtual string name() const { return itemp()->name(); }
virtual bool broken() const { return !itemp(); }
virtual const char* broken() const { BROKEN_RTN(!itemp()); return NULL; }
virtual int instrCount() const { return 0; }
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); }
virtual bool same(AstNode* samep) const {
@@ -601,8 +652,8 @@ public:
m_uniqueNum = uniqueNumInc();
}
ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE)
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -620,6 +671,7 @@ public:
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
@@ -843,6 +895,7 @@ private:
bool m_isStatic:1; // Static variable
bool m_isPulldown:1; // Tri0
bool m_isPullup:1; // Tri1
bool m_isIfaceParent:1; // dtype is reference to interface present in this module
bool m_trace:1; // Trace this variable
void init() {
@@ -854,6 +907,7 @@ private:
m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
m_isIfaceParent=false;
m_trace=false;
}
public:
@@ -917,7 +971,7 @@ public:
void combineType(AstVarType type);
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
@@ -944,6 +998,7 @@ public:
void primaryIO(bool flag) { m_primaryIO = flag; }
void isConst(bool flag) { m_isConst = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; }
@@ -959,6 +1014,8 @@ public:
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output); }
bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
|| varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); }
@@ -1079,7 +1136,7 @@ public:
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
ASTNODE_NODE_FUNCS(Scope, SCOPE)
virtual void cloneRelink();
virtual bool broken() const;
virtual const char* broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
virtual void name(const string& name) { m_name = name; }
@@ -1133,8 +1190,8 @@ public:
UASSERT(m_scopep->clonep(), "No clone cross link: "<<this);
m_scopep = m_scopep->clonep()->castScope();
}}
virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists())
|| (m_scopep && !m_scopep->brokeExists())); }
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists());
BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name
virtual void dump(ostream& str);
@@ -1234,7 +1291,7 @@ public:
}
ASTNODE_NODE_FUNCS(Pin, PIN)
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modVarp && !m_modVarp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); return NULL; }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; }
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
@@ -1247,6 +1304,25 @@ public:
void svImplicit(bool flag) { m_svImplicit=flag; }
};
struct AstArg : public AstNode {
// An argument to a function/task
private:
string m_name; // Pin name, or "" for number based interconnect
public:
AstArg(FileLine* fl, const string& name, AstNode* exprp)
: AstNode(fl)
,m_name(name) {
setNOp1p(exprp);
}
ASTNODE_NODE_FUNCS(Arg, ARG)
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; }
virtual V3Hash sameHash() const { return V3Hash(); }
void exprp(AstNode* nodep) { addOp1p(nodep); }
AstNode* exprp() const { return op1p()->castNode(); } // op1 = Expression connected to pin, NULL if unconnected
bool emptyConnectNoNext() const { return !exprp() && name()=="" && !nextp(); }
};
struct AstModule : public AstNodeModule {
// A module declaration
AstModule(FileLine* fl, const string& name)
@@ -1290,7 +1366,7 @@ public:
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
: AstNode (fl), m_name(name), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageImport, PACKAGEIMPORT)
virtual bool broken() const { return (!m_packagep || !m_packagep->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep()->castPackage(); }
virtual void dump(ostream& str);
virtual string name() const { return m_name; }
@@ -1298,6 +1374,49 @@ public:
void packagep(AstPackage* nodep) { m_packagep=nodep; }
};
struct AstIface : public AstNodeModule {
// A module declaration
AstIface(FileLine* fl, const string& name)
: AstNodeModule (fl,name) { }
ASTNODE_NODE_FUNCS(Iface, IFACE)
};
struct AstModportVarRef : public AstNode {
// A input/output/etc variable referenced under a modport
// The storage for the variable itself is inside the interface, thus this is a reference
// PARENT: AstIface
private:
string m_name; // Name of the variable referenced
AstVarType m_type; // Type of the variable (in/out)
AstVar* m_varp; // Link to the actual Var
public:
AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type)
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
virtual void dump(ostream& str);
AstVarType varType() const { return m_type; } // * = Type of variable
virtual string name() const { return m_name; }
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp=varp; }
};
struct AstModport : public AstNode {
// A modport in an interface
private:
string m_name; // Name of the modport
public:
AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
: AstNode(fl), m_name(name) {
addNOp1p(varsp); }
virtual string name() const { return m_name; }
virtual bool maybePointedTo() const { return true; }
ASTNODE_NODE_FUNCS(Modport, MODPORT)
AstModportVarRef* varsp() const { return op1p()->castModportVarRef(); } // op1 = List of Vars
};
struct AstCell : public AstNode {
// A instantiation cell or interface call (don't know which until link)
private:
@@ -1305,17 +1424,18 @@ private:
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
bool m_hasIfaceVar; // True if a Var has been created for this cell
public:
AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: AstNode(fl)
, m_name(instName), m_origName(instName), m_modName(modName)
, m_modp(NULL) {
, m_modp(NULL), m_hasIfaceVar(false) {
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
ASTNODE_NODE_FUNCS(Cell, CELL)
// No cloneRelink, we presume cloneee's want the same module linkages
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
@@ -1331,6 +1451,8 @@ public:
void addPinsp(AstPin* nodep) { addOp1p(nodep); }
void addParamsp(AstPin* nodep) { addOp2p(nodep); }
void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
};
struct AstCellInline : public AstNode {
@@ -1440,7 +1562,7 @@ public:
: AstNode(fl), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageRef, PACKAGEREF)
// METHODS
virtual bool broken() const { return !m_packagep || !m_packagep->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) {
m_packagep = m_packagep->clonep()->castPackage();
}}
@@ -1713,6 +1835,16 @@ struct AstAssignW : public AstNodeAssign {
}
};
struct AstAssignVarScope : public AstNodeAssign {
// Assign two VarScopes to each other
AstAssignVarScope(FileLine* fileline, AstNode* lhsp, AstNode* rhsp)
: AstNodeAssign(fileline, lhsp, rhsp) {
dtypeFrom(rhsp);
}
ASTNODE_NODE_FUNCS(AssignVarScope, ASSIGNVARSCOPE)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
};
struct AstPull : public AstNode {
private:
bool m_direction;
@@ -1799,10 +1931,10 @@ public:
m_dataDeclp = NULL;
}
ASTNODE_NODE_FUNCS(CoverDecl, COVERDECL)
virtual bool broken() const {
if (m_dataDeclp && !m_dataDeclp->brokeExists()) return true;
virtual const char* broken() const {
BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists());
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) v3fatalSrc("dataDeclp should point to real data, not be a list"); // Avoid O(n^2) accessing
return false; }
return NULL; }
virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1840,7 +1972,7 @@ public:
m_declp = declp;
}
ASTNODE_NODE_FUNCS(CoverInc, COVERINC)
virtual bool broken() const { return !declp()->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1991,7 +2123,7 @@ public:
}
ASTNODE_NODE_FUNCS(Display, DISPLAY)
virtual void dump(ostream& str);
virtual bool broken() const { return !fmtp(); }
virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii()
: (string)"$"+(string)displayType().ascii()); }
virtual bool isGateOptimizable() const { return false; }
@@ -2021,7 +2153,7 @@ struct AstSFormat : public AstNode {
setOp3p(lhsp);
}
ASTNODE_NODE_FUNCS(SFormat, SFORMAT)
virtual bool broken() const { return !fmtp(); }
virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return "$sformat"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
@@ -2442,7 +2574,7 @@ public:
m_labelp = labelp;
}
ASTNODE_NODE_FUNCS(JumpGo, JUMPGO)
virtual bool broken() const { return !labelp()->brokeExistsAbove(); }
virtual const char* broken() const { BROKEN_RTN(!labelp()->brokeExistsAbove()); return NULL; }
virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return instrCountBranch(); }
@@ -2719,7 +2851,7 @@ public:
addNOp2p(valuep);
}
ASTNODE_NODE_FUNCS(TraceInc, TRACEINC)
virtual bool broken() const { return !declp()->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castTraceDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 10+2*instrCountLd(); }
@@ -2756,7 +2888,7 @@ public:
ASTNODE_NODE_FUNCS(Active, ACTIVE)
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; }
virtual bool broken() const { return (m_sensesp && !m_sensesp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return NULL; }
virtual void cloneRelink() {
if (m_sensesp->clonep()) {
m_sensesp = m_sensesp->clonep()->castSenTree();
@@ -3256,6 +3388,7 @@ struct AstFEof : public AstNodeUniop {
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*16; }
virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
};
@@ -3269,6 +3402,7 @@ struct AstFGetC : public AstNodeUniop {
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*64; }
virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering
AstNode* filep() const { return lhsp(); }
};
@@ -4358,7 +4492,7 @@ public:
}
ASTNODE_NODE_FUNCS(CFunc, CFUNC)
virtual string name() const { return m_name; }
virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); }
virtual const char* broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual void dump(ostream& str=cout);
virtual V3Hash sameHash() const { return V3Hash(); }
@@ -4446,7 +4580,7 @@ public:
virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) {
m_funcp = m_funcp->clonep()->castCFunc();
}}
virtual bool broken() const { return (m_funcp && !m_funcp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; }
virtual int instrCount() const { return instrCountCall(); }
virtual V3Hash sameHash() const { return V3Hash(funcp()); }
virtual bool same(AstNode* samep) const {
@@ -4578,7 +4712,7 @@ public:
m_dollarUnitPkgp = NULL;
}
ASTNODE_NODE_FUNCS(Netlist, NETLIST)
virtual bool broken() const { return (m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); return NULL; }
AstNodeModule* modulesp() const { return op1p()->castNodeModule();} // op1 = List of modules
AstNodeModule* topModulep() const { return op1p()->castNodeModule(); } // * = Top module in hierarchy (first one added, for now)
void addModulep(AstNodeModule* modulep) { addOp1p(modulep); }
+2 -2
View File
@@ -202,8 +202,8 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::setUnder(nodep,true);
if (nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)");
if (const char* whyp=nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
}
if (nodep->dtypep()) {
if (!nodep->dtypep()->brokeExists()) { nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep()); }
+1 -1
View File
@@ -526,7 +526,7 @@ private:
}
}
}
sort(report.begin(), report.end());
stable_sort(report.begin(), report.end());
for (deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
*ofp << *it;
}
+1 -1
View File
@@ -89,7 +89,7 @@ private:
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
bool isArray = arrayp;
bool isStruct = structp && structp->packed();
bool isStruct = structp && structp->packedUnsup();
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)
+4 -8
View File
@@ -346,14 +346,10 @@ private:
nodep->iterateChildren(*this);
// Link to global function
if (nodep->formCallTree()) {
if (nodep->name() == "_final") {
UINFO(4, " formCallTree "<<nodep<<endl);
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
callp->argTypes("vlSymsp");
m_finalFuncp->addStmtsp(callp);
} else {
nodep->v3fatalSrc("Unknown CFunc name. Make code more generic, with a map of func names");
}
UINFO(4, " formCallTree "<<nodep<<endl);
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
callp->argTypes("vlSymsp");
m_finalFuncp->addStmtsp(callp);
}
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
+12 -3
View File
@@ -815,9 +815,10 @@ private:
bool varNotReferenced(AstNode* nodep, AstVar* varp, int level=0) {
// Return true if varp never referenced under node.
// Return false if referenced, or tree too deep to be worth it
// Return false if referenced, or tree too deep to be worth it, or side effects
if (!nodep) return true;
if (level>2) return false;
if (nodep->isPure()) return false; // For example a $fgetc can't be reordered
if (nodep->castNodeVarRef() && nodep->castNodeVarRef()->varp()==varp) return false;
return (varNotReferenced (nodep->nextp(),varp,level+1)
&& varNotReferenced(nodep->op1p(),varp,level+1)
@@ -1230,6 +1231,8 @@ private:
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
&& !(nodep->varp()->isFuncLocal() // Default value, not a "known" constant for this usage
&& nodep->varp()->isInput())
&& !nodep->varp()->isSigPublic())
|| nodep->varp()->isParam())) {
AstConst* constp = nodep->varp()->valuep()->castConst();
@@ -1413,7 +1416,7 @@ private:
for (AstNodeSenItem* senp = nodep->sensesp()->castNodeSenItem(); senp; senp=senp->nextp()->castNodeSenItem()) {
vec.push_back(senp);
}
sort(vec.begin(), vec.end(), SenItemCmp());
stable_sort(vec.begin(), vec.end(), SenItemCmp());
for (vector<AstNodeSenItem*>::iterator it=vec.begin(); it!=vec.end(); ++it) {
(*it)->unlinkFrBack();
}
@@ -1466,6 +1469,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Don't perform any optimizations, keep the alias around
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Don't perform any optimizations, the node won't be linked yet
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst && replaceNodeAssign(nodep)) return;
@@ -1640,7 +1646,10 @@ private:
replaceWithSimulation(nodep);
}
}
virtual void visit(AstArg* nodep, AstNUser*) {
// replaceWithSimulation on the Arg's parent FuncRef replaces these
nodep->iterateChildren(*this);
}
virtual void visit(AstWhile* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst) {
+53 -5
View File
@@ -64,6 +64,7 @@ private:
bool m_checkBlock; // Should this block get covered?
AstNodeModule* m_modp; // Current module to add statement to
bool m_inToggleOff; // In function/task etc
bool m_inModOff; // In module with no coverage
FileMap m_fileps; // Column counts for each fileline
string m_beginHier; // AstBegin hier name for user coverage points
@@ -124,9 +125,11 @@ private:
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
m_fileps.clear();
nodep->iterateChildren(*this);
m_modp = NULL;
m_inModOff = true;
}
// VISITORS - TOGGLE COVERAGE
@@ -140,7 +143,7 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_modp && !m_inToggleOff
if (m_modp && !m_inModOff && !m_inToggleOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) {
const char* disablep = varIgnoreToggle(nodep);
if (disablep) {
@@ -210,7 +213,7 @@ private:
}
}
else if (AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) {
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code),
@@ -221,6 +224,50 @@ private:
newent.cleanup();
}
}
else if (AstPackArrayDType* adtypep = dtypep->castPackArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) {
AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp();
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
index_code*subtypep->width(), subtypep->width()),
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true),
index_code*subtypep->width(), subtypep->width()));
toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else if (AstStructDType* adtypep = dtypep->castStructDType()) {
// For now it's packed, so similar to array
for (AstMemberDType* itemp = adtypep->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
int index_code = itemp->lsb();
ToggleEnt newent (above.m_comment+string(".")+itemp->name(),
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
index_code, subtypep->width()),
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true),
index_code, subtypep->width()));
toggleVarRecurse(subtypep, depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else if (AstUnionDType* adtypep = dtypep->castUnionDType()) {
// Arbitrarially handle only the first member of the union
if (AstMemberDType* itemp = adtypep->membersp()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent (above.m_comment+string(".")+itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true));
toggleVarRecurse(subtypep, depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else {
dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<<dtypep->prettyTypeName());
}
@@ -231,7 +278,7 @@ private:
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it
if (!nodep->backp()->castIf()
|| nodep->backp()->castIf()->elsesp()!=nodep) { // Ignore if else; did earlier
@@ -243,7 +290,7 @@ private:
if (nodep->elsesp()) {
m_checkBlock = true;
nodep->elsesp()->iterateAndNext(*this);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->elsesp()->castIf()) {
@@ -258,7 +305,7 @@ private:
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
UINFO(4," CASEI: "<<nodep<<endl);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) {
nodep->bodysp()->iterateAndNext(*this);
if (m_checkBlock) { // if the case body didn't disable it
@@ -327,6 +374,7 @@ public:
m_checkBlock = true;
m_beginHier = "";
m_inToggleOff = false;
m_inModOff = true;
rootp->iterateChildren(*this);
}
virtual ~CoverageVisitor() {}
+3 -3
View File
@@ -124,10 +124,10 @@ private:
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
VarMap::iterator iter = m_modVarMap.find(make_pair(addmodp,name));
if (iter != m_modVarMap.end()) {
VarMap::iterator it = m_modVarMap.find(make_pair(addmodp,name));
if (it != m_modVarMap.end()) {
// Created module's AstVar earlier under some other scope
varp = iter->second;
varp = it->second;
} else {
if (width==0) {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
+34 -41
View File
@@ -58,8 +58,9 @@ public:
int splitFilenum() const { return m_splitFilenum; }
int splitFilenumInc() { m_splitSize = 0; return ++m_splitFilenum; }
int splitSize() const { return m_splitSize; }
void splitSizeInc(AstNode* nodep) { m_splitSize += EmitCBaseCounterVisitor(nodep).count(); }
bool splitNeeded() { return (splitSize() && v3Global.opt.outputSplit() > 1
void splitSizeInc(int count) { m_splitSize += count; }
void splitSizeInc(AstNode* nodep) { splitSizeInc(EmitCBaseCounterVisitor(nodep).count()); }
bool splitNeeded() { return (splitSize() && v3Global.opt.outputSplit()
&& v3Global.opt.outputSplit() < splitSize()); }
// METHODS
@@ -86,6 +87,13 @@ public:
}
void emitOpName(AstNode* nodep, const string& format,
AstNode* lhsp, AstNode* rhsp, AstNode* thsp);
void emitDeclArrayBrackets(AstVar* nodep) {
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
@@ -788,7 +796,7 @@ class EmitCImp : EmitCStmts {
if (!m_blkChangeDetVec.empty()) puts("return __req;\n");
// puts("__Vm_activity = true;\n");
//puts("__Vm_activity = true;\n");
puts("}\n");
}
@@ -875,7 +883,6 @@ public:
void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
AstBasicDType* basicp = nodep->basicp(); if (!basicp) nodep->v3fatalSrc("Unimplemented: Outputting this data type");
if (nodep->isIO()) {
bool isArray = !nodep->dtypeSkipRefp()->castBasicDType();
if (nodep->isSc()) {
m_ctorVarsVec.push_back(nodep);
ofp()->putAlign(nodep->isStatic(), 4); // sc stuff is a structure, so bigger alignment
@@ -891,12 +898,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
puts(">\t");
}
puts(nodep->name());
if (isArray) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
}
emitDeclArrayBrackets(nodep);
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
@@ -909,36 +911,20 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->isQuad()) puts("64");
else if (nodep->widthMin() <= 8) puts("8");
else if (nodep->widthMin() <= 16) puts("16");
else if (nodep->isWide()) puts("W");
if (isArray) {
if (nodep->isWide()) puts("W");
puts("("+nodep->name());
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(","+cvtToStr(basicp->msb())+","+cvtToStr(basicp->lsb()));
if (basicp->isWide()) puts(","+cvtToStr(basicp->widthWords()));
} else {
if (!basicp->isWide())
puts("("+nodep->name()
+","+cvtToStr(basicp->msb())
+","+cvtToStr(basicp->lsb()));
else puts("W("+nodep->name()
+","+cvtToStr(basicp->msb())
+","+cvtToStr(basicp->lsb())
+","+cvtToStr(basicp->widthWords()));
}
puts("("+nodep->name());
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
} else if (basicp && basicp->isOpaque()) {
// strings and other fundamental c types
puts(nodep->vlArgType(true,false));
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
emitDeclArrayBrackets(nodep);
puts(";\n");
} else {
// Arrays need a small alignment, but may need different padding after.
@@ -960,13 +946,10 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
puts(","+cvtToStr(basicp->lsb()+nodep->width())+","+cvtToStr(basicp->lsb()));
puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
@@ -1436,9 +1419,11 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
puts("// Coverage Declarations\n");
}
nodep->accept(*this);
splitSizeInc(nodep);
}
}
puts("}\n");
splitSizeInc(10);
}
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
@@ -1462,6 +1447,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
puts( " \"page\",pagep,");
puts( " \"comment\",commentp);\n");
puts("}\n");
splitSizeInc(10);
}
}
@@ -1471,6 +1457,7 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) {
emitTextSection(AstType::atSCDTOR);
if (modp->isTop()) puts("delete __VlSymsp; __VlSymsp=NULL;\n");
puts("}\n");
splitSizeInc(10);
}
void EmitCImp::emitSavableImp(AstNodeModule* modp) {
@@ -1649,6 +1636,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts("}\n");
#endif
puts("}\n");
splitSizeInc(10);
//
puts("\nvoid "+modClassName(modp)+"::_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+") {\n");
@@ -1669,6 +1657,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts( "}\n");
#endif
puts("}\n");
splitSizeInc(10);
}
//----------------------------------------------------------------------
@@ -1735,7 +1724,7 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
}
}
sort(funcsp.begin(), funcsp.end(), CmpName());
stable_sort(funcsp.begin(), funcsp.end(), CmpName());
for (vector<AstCFunc*>::iterator it = funcsp.begin(); it != funcsp.end(); ++it) {
AstCFunc* funcp = *it;
@@ -2129,6 +2118,7 @@ class EmitCTrace : EmitCStmts {
+", &"+topClassName()+"::traceFull"
+", &"+topClassName()+"::traceChg, this);\n");
puts("}\n");
splitSizeInc(10);
puts("void "+topClassName()+"::traceInit("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
@@ -2141,6 +2131,7 @@ class EmitCTrace : EmitCStmts {
puts("t->traceInitThis (vlSymsp, vcdp, code);\n");
puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break
puts("}\n");
splitSizeInc(10);
puts("void "+topClassName()+"::traceFull("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
@@ -2149,6 +2140,7 @@ class EmitCTrace : EmitCStmts {
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("t->traceFullThis (vlSymsp, vcdp, code);\n");
puts("}\n");
splitSizeInc(10);
puts("\n//======================\n\n");
}
@@ -2165,6 +2157,7 @@ class EmitCTrace : EmitCStmts {
puts("t->traceChgThis (vlSymsp, vcdp, code);\n");
puts("}\n");
puts("}\n");
splitSizeInc(10);
puts("\n//======================\n\n");
}
+2 -2
View File
@@ -168,8 +168,8 @@ class EmitCSyms : EmitCBaseVisitor {
varsExpand();
// Sort by names, so line/process order matters less
sort(m_scopes.begin(), m_scopes.end(), CmpName());
sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
// Output
emitSymHdr();
+3
View File
@@ -525,6 +525,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
nodep->pinsp()->iterateAndNext(*this);
puts(")");
}
virtual void visit(AstArg* nodep, AstNUser*) {
nodep->exprp()->iterateAndNext(*this);
}
// Terminals
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (nodep->varScopep())
+10 -3
View File
@@ -44,6 +44,7 @@ bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX];
bool V3Error::s_describedWarnings = false;
bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX];
V3Error::MessagesSet V3Error::s_messages;
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
@@ -89,8 +90,8 @@ const string FileLineSingleton::filenameLetters(int no) {
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
FileNameNumMap::const_iterator iter = m_namemap.find(filename);
if (VL_LIKELY(iter != m_namemap.end())) return iter->second;
FileNameNumMap::const_iterator it = m_namemap.find(filename);
if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
m_languages.push_back(V3LangCode::mostRecent());
@@ -482,7 +483,8 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
}
#ifndef _V3ERROR_NO_GLOBAL_
if (debug()) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",99));
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",990));
if (s_errorExitCb) s_errorExitCb();
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
@@ -491,5 +493,10 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
vlAbort();
}
else if (isError(s_errorCode, s_errorSuppressed)) {
// We don't dump tree on any error because a Visitor may be in middle of
// a tree cleanup and cause a false broken problem.
if (s_errorExitCb) s_errorExitCb();
}
}
}
+6 -1
View File
@@ -93,6 +93,7 @@ public:
UNDRIVEN, // No drivers
UNOPT, // Unoptimizable block
UNOPTFLAT, // Unoptimizable block after flattening
UNPACKED, // Unsupported unpacked
UNSIGNED, // Comparison is constant due to unsigned arithmetic
UNUSED, // No receivers
VARHIDDEN, // Hiding variable
@@ -129,7 +130,7 @@ public:
"PINMISSING", "PINNOCONNECT",
"REALCVT", "REDEFMACRO",
"SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNPACKED", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
" MAX"
};
@@ -181,6 +182,7 @@ class V3Error {
// Base class for any object that wants debugging and error reporting
typedef set<string> MessagesSet;
typedef void (*ErrorExitCb)(void);
private:
static bool s_describedWarnings; // Told user how to disable warns
@@ -194,6 +196,8 @@ class V3Error {
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
V3Error() { cerr<<("Static class"); abort(); }
@@ -218,6 +222,7 @@ class V3Error {
static bool isError(V3ErrorCode code, bool supp);
static string lineStr (const char* filename, int lineno);
static V3ErrorCode errorCode() { return s_errorCode; }
static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; }
// When printing an error/warning, print prefix for multiline message
static string warnMore();
+1 -1
View File
@@ -215,7 +215,7 @@ private:
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
m_substTreep = nodep->rhsp();
if (!nodep->lhsp()->castNodeVarRef())
clearSimple("ASSIGN(non VARREF)");
clearSimple("ASSIGN(non-VARREF)");
else nodep->iterateChildren(*this);
// We don't push logic other then assignments/NOTs into SenItems
// This avoids a mess in computing what exactly a POSEDGE is
+2 -2
View File
@@ -74,13 +74,13 @@ public:
// METHODS
void readFiles();
void checkTree();
static void dumpGlobalTree(const string& filename, int newNumber=0);
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
string debugFilename(const string& nameComment, int newNumber=0) {
++m_debugFileNumber;
if (newNumber) m_debugFileNumber = newNumber;
char digits[100]; sprintf(digits, "%02d", m_debugFileNumber);
char digits[100]; sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment;
}
bool needHInlines() const { return m_needHInlines; }
+1 -1
View File
@@ -461,7 +461,7 @@ void GraphAcyc::place() {
}
// Sort by weight, then by vertex (so that we completely process one vertex, when possible)
sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
stable_sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
// Process each edge in weighted order
m_placeStep = 10;
+2 -2
View File
@@ -464,7 +464,7 @@ void V3Graph::sortVertices() {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
vertices.push_back(vertexp);
}
std::sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
this->verticesUnlink();
for (vector<V3GraphVertex*>::iterator it = vertices.begin(); it!=vertices.end(); ++it) {
(*it)->verticesPushBack(this);
@@ -480,7 +480,7 @@ void V3Graph::sortEdges() {
edges.push_back(edgep);
}
// Sort
std::sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
std::stable_sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
// Relink edges in specified order
// We know the vector contains all of the edges that were
+378 -278
View File
@@ -42,11 +42,376 @@
#include "V3Stats.h"
#include "V3Ast.h"
// CONFIG
static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
//######################################################################
// Inline state, as a visitor of each AstNode
// CONFIG
static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
class InlineMarkVisitor : public AstNVisitor {
private:
// NODE STATE
// Output
// AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
// Entire netlist (can be cleared after this visit completes)
// AstNodeModule::user2() // CIL_*. Allowed to automatically inline module
// AstNodeModule::user3() // int. Number of cells referencing this module
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
enum {CIL_NOTHARD=0, // For user2, inline not supported
CIL_NOTSOFT, // For user2, don't inline unless user overrides
CIL_MAYBE}; // For user2, might inline
// STATE
AstNodeModule* m_modp; // Flattened cell's containing module
int m_stmtCnt; // Statements in module
V3Double0 m_statUnsup; // Statistic tracking
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void cantInline(const char* reason, bool hard) {
if (hard) {
if (m_modp->user2() != CIL_NOTHARD) {
UINFO(4," No inline hard: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(CIL_NOTHARD);
m_statUnsup++;
}
} else {
if (m_modp->user2() == CIL_MAYBE) {
UINFO(4," No inline soft: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(CIL_NOTSOFT);
}
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_stmtCnt = 0;
m_modp = nodep;
m_modp->user2(CIL_MAYBE);
if (m_modp->castIface()) {
// Inlining an interface means we no longer have a cell handle to resolve to.
// If inlining moves post-scope this can perhaps be relaxed.
cantInline("modIface",true);
}
if (m_modp->modPublic()) cantInline("modPublic",false);
//
nodep->iterateChildren(*this);
//
bool userinline = nodep->user1();
int allowed = nodep->user2();
int refs = nodep->user3();
// Should we automatically inline this module?
// inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
bool doit = ((allowed == CIL_NOTSOFT || allowed == CIL_MAYBE)
&& (userinline
|| ((allowed == CIL_MAYBE)
&& (refs==1
|| m_stmtCnt < INLINE_MODS_SMALLER
|| v3Global.opt.inlineMult() < 1
|| refs*m_stmtCnt < v3Global.opt.inlineMult()))));
// Packages aren't really "under" anything so they confuse this algorithm
if (nodep->castPackage()) doit = false;
UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
<<" "<<nodep<<endl);
nodep->user1(doit);
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->modp()->user3Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
m_modp->user1(1);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
cantInline("Pragma NO_INLINE_MODULE",false);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->varp(NULL);
}
virtual void visit(AstVar* nodep, AstNUser*) {
// Can't look at AstIfaceRefDType directly as it is no longer underneath the module
if (nodep->isIfaceRef()) {
// Unsupported: Inlining of modules with ifaces (see AstIface comment above)
if (m_modp) cantInline("Interfaced",true);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
if (!nodep->packagep()) nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Don't count assignments, as they'll likely flatten out
// Still need to iterate though to nullify VarXRefs
int oldcnt = m_stmtCnt;
nodep->iterateChildren(*this);
m_stmtCnt = oldcnt;
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
public:
// CONSTUCTORS
InlineMarkVisitor(AstNode* nodep) {
m_modp = NULL;
m_stmtCnt = 0;
nodep->accept(*this);
}
virtual ~InlineMarkVisitor() {
V3Stats::addStat("Optimizations, Inline unsupported", m_statUnsup);
// Done with these, are not outputs
AstNode::user2ClearTree();
AstNode::user3ClearTree();
}
};
//######################################################################
// Using clonep(), find cell cross references.
// clone() must not be called inside this visitor
class InlineCollectVisitor : public AstNVisitor {
private:
// NODE STATE
// Output:
// AstCell::user4p() // AstCell* of the created clone
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->user4p(nodep->clonep());
}
// Accelerate
virtual void visit(AstNodeStmt* nodep, AstNUser*) {}
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
InlineCollectVisitor(AstNodeModule* nodep) { // passed OLD module, not new one
nodep->accept(*this);
}
virtual ~InlineCollectVisitor() {}
};
//######################################################################
// After cell is cloned, relink the new module's contents
class InlineRelinkVisitor : public AstNVisitor {
private:
// NODE STATE
// Input:
// See InlineVisitor
// STATE
AstNodeModule* m_modp; // Current module
AstCell* m_cellp; // Cell being cloned
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstCellInline* nodep, AstNUser*) {
// Inlined cell under the inline cell, need to move to avoid conflicts
nodep->unlinkFrBack();
m_modp->addInlinesp(nodep);
// Rename
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
UINFO(6, " Inline "<<nodep<<endl);
// Do CellInlines under this, but don't move them
nodep->iterateChildren(*this);
}
virtual void visit(AstCell* nodep, AstNUser*) {
// Cell under the inline cell, need to rename to avoid conflicts
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
nodep->iterateChildren(*this);
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (nodep->user2p()) {
// Make an assignment, so we'll trace it properly
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
} else if (nodep->user3()) {
// Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might remove the change detection
// on the output variable.
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
} else {
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
}
}
// Variable under the inline cell, need to rename to avoid conflicts
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
// Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
if (AstIfaceRefDType* ifacerefp = nodep->dtypep()->castIfaceRefDType()) {
// Relink to point to newly cloned cell
if (ifacerefp->cellp()) {
if (AstCell* newcellp = ifacerefp->cellp()->user4p()->castNode()->castCell()) {
ifacerefp->cellp(newcellp);
ifacerefp->cellName(newcellp->name());
}
}
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
// Function under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
// Typedef under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {
nodep->replaceWith(exprconstp->cloneTree(true));
nodep->deleteTree(); nodep=NULL;
return;
}
else if (exprvarrefp) {
nodep->varp( exprvarrefp->varp() );
}
else {
nodep->v3fatalSrc("Null connection?\n");
}
}
nodep->name(nodep->varp()->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
nodep->iterateChildren(*this);
}
// Not needed, as V3LinkDot doesn't care about typedefs
//virtual void visit(AstRefDType* nodep, AstNUser*) {}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Begin
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
// Fix path in coverage statements
nodep->hier(m_cellp->prettyName()
+ (nodep->hier()!="" ? ".":"")
+ nodep->hier());
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
InlineRelinkVisitor(AstNodeModule* cloneModp, AstNodeModule* oldModp, AstCell* cellp) {
m_modp = oldModp;
m_cellp = cellp;
cloneModp->accept(*this);
}
virtual ~InlineRelinkVisitor() {}
};
//######################################################################
// Inline state, as a visitor of each AstNode
class InlineVisitor : public AstNVisitor {
private:
@@ -56,11 +421,13 @@ private:
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
// Cleared each cell
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
// AstVar::user3() // bool Don't alias the user4, keep it as signal
// AstVar::user3() // bool Don't alias the user2, keep it as signal
// AstCell::user4 // AstCell* of the created clone
AstUser4InUse m_inuser4;
// STATE
AstNodeModule* m_modp; // Current module
AstCell* m_cellp; // Cell being cloned
V3Double0 m_statCells; // Statistic tracking
static int debug() {
@@ -75,34 +442,11 @@ private:
nodep->iterateChildrenBackwards(*this);
}
virtual void visit(AstNodeModule* nodep, AstNUser*) {
if (m_cellp) {
} else {
m_modp = nodep;
}
m_modp = nodep;
nodep->iterateChildren(*this);
}
virtual void visit(AstCellInline* nodep, AstNUser*) {
// Inlined cell under the inline cell, need to move to avoid conflicts
if (m_cellp) {
nodep->unlinkFrBack();
m_modp->addInlinesp(nodep);
// Rename
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
UINFO(6, " Inline "<<nodep<<endl);
// Do CellInlines under this, but don't move them
nodep->iterateChildren(*this);
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
if (m_cellp) {
// Cell under the inline cell, need to rename to avoid conflicts
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
nodep->iterateChildren(*this);
}
if (nodep->modp()->user1()) { // Marked with inline request
if (m_cellp) nodep->v3error("Cloning should have already been done bottom-up");
UINFO(5," Inline CELL "<<nodep<<endl);
UINFO(5," To MOD "<<m_modp<<endl);
++m_statCells;
@@ -121,8 +465,10 @@ private:
//if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); }
// Clear var markings
// Clear var markings and find cell cross references
AstNode::user2ClearTree();
AstNode::user4ClearTree();
{ InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately
// Create data for dotted variable resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
nodep->name(), nodep->modp()->origName());
@@ -163,9 +509,7 @@ private:
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
}
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterate(*this); // Not iterateAndNext because newmodp isn't linked; no back
m_cellp = NULL;
{ InlineRelinkVisitor(newmodp, m_modp, nodep); }
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
AstNode* stmtsp = newmodp->stmtsp();
@@ -178,133 +522,10 @@ private:
if (debug()>=9) { m_modp->dumpTree(cout,"donemod:"); }
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->user2p()) {
// Make an assignment, so we'll trace it properly
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
} else if (nodep->user3()) {
// Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might remove the change detection
// on the output variable.
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else {
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
}
}
// Variable under the inline cell, need to rename to avoid conflicts
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
}
if (nodep) nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
if (m_cellp) {
// Function under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
if (m_cellp) {
// Typedef under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {
nodep->replaceWith(exprconstp->cloneTree(true));
nodep->deleteTree(); nodep=NULL;
return;
}
else if (exprvarrefp) {
nodep->varp( exprvarrefp->varp() );
}
else {
nodep->v3fatalSrc("Null connection?\n");
}
}
nodep->name(nodep->varp()->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
if (m_cellp) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (m_cellp) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
}
nodep->iterateChildren(*this);
}
// Not needed, as V3LinkDot doesn't care about typedefs
//virtual void visit(AstRefDType* nodep, AstNUser*) {}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Begin
if (m_cellp) {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
// Fix path in coverage statements
if (m_cellp) {
nodep->hier(m_cellp->prettyName()
+ (nodep->hier()!="" ? ".":"")
+ nodep->hier());
}
nodep->iterateChildren(*this);
}
//--------------------
// Default: Just iterate
virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNodeStmt* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
@@ -312,7 +533,6 @@ private:
public:
// CONSTUCTORS
InlineVisitor(AstNode* nodep) {
m_cellp = NULL;
m_modp = NULL;
nodep->accept(*this);
}
@@ -321,126 +541,6 @@ public:
}
};
//######################################################################
// Inline state, as a visitor of each AstNode
class InlineMarkVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist
// AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
// AstNodeModule::user2() // bool. Allowed to automatically inline module
// AstNodeModule::user3() // int. Number of cells referencing this module
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// STATE
AstNodeModule* m_modp; // Current module
int m_stmtCnt; // Statements in module
// METHODS
void cantInline(const char* reason) {
if (m_modp->user2()) {
UINFO(4," No inline: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(false);
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_stmtCnt = 0;
m_modp = nodep;
m_modp->user2(true); // Allowed = true
if (m_modp->modPublic()) cantInline("modPublic");
//
nodep->iterateChildren(*this);
//
bool userinline = nodep->user1();
bool allowed = nodep->user2();
int refs = nodep->user3();
// Should we automatically inline this module?
// inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
bool doit = (userinline || (allowed && (refs==1
|| m_stmtCnt < INLINE_MODS_SMALLER
|| v3Global.opt.inlineMult() < 1
|| refs*m_stmtCnt < v3Global.opt.inlineMult())));
// Packages aren't really "under" anything so they confuse this algorithm
if (nodep->castPackage()) doit = false;
UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
<<" "<<nodep<<endl);
if (doit) {
UINFO(4," AutoInline "<<nodep<<endl);
nodep->user1(true);
}
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->modp()->user3Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
m_modp->user1(1);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
cantInline("Pragma NO_INLINE_MODULE");
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->varp(NULL);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
if (!nodep->packagep()) nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Don't count assignments, as they'll likely flatten out
// Still need to iterate though to nullify VarXRefs
int oldcnt = m_stmtCnt;
nodep->iterateChildren(*this);
m_stmtCnt = oldcnt;
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
public:
// CONSTUCTORS
InlineMarkVisitor(AstNode* nodep) {
m_modp = NULL;
m_stmtCnt = 0;
//VV***** We reset all userp() on the whole netlist!!!
AstNode::user1ClearTree();
AstNode::user2ClearTree();
AstNode::user3ClearTree();
nodep->accept(*this);
}
virtual ~InlineMarkVisitor() {}
};
//######################################################################
// Inline class functions
+12 -1
View File
@@ -105,6 +105,13 @@ private:
exprp);
m_modp->addStmtp(assp);
if (debug()>=9) assp->dumpTree(cout," _new: ");
} else if (nodep->modVarp()->isIfaceRef()) {
// Create an AstAssignVarScope for Vars to Cells so we can link with their scope later
AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstVarRef* refp = exprp->castVarRef();
if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp);
m_modp->addStmtp(assp);
} else {
nodep->v3error("Assigned pin is neither input nor output");
}
@@ -252,7 +259,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
&& connectRefp
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
// Done. Same data type
// Done. Same data type
} else if (!alwaysCvt
&& connectRefp
&& connectRefp->varp()->isIfaceRef()) {
// Done. Interface
} else if (!alwaysCvt
&& connBasicp
&& pinBasicp
+3 -3
View File
@@ -37,9 +37,9 @@ class V3LanguageWords {
}
public:
string isKeyword(const string& kwd) {
map<string,string>::iterator iter = m_kwdMap.find(kwd);
if (iter == m_kwdMap.end()) return "";
return iter->second;
map<string,string>::iterator it = m_kwdMap.find(kwd);
if (it == m_kwdMap.end()) return "";
return it->second;
}
public:
+37
View File
@@ -190,6 +190,7 @@ private:
<<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName());
}
}
if (nodep->castIface() || nodep->castPackage()) nodep->inLibrary(true); // Interfaces can't be at top, unless asked
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
if (topMatch) {
m_topVertexp = vertex(nodep);
@@ -210,6 +211,25 @@ private:
m_modp = NULL;
}
virtual void visit(AstIfaceRefDType* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
if (modp) {
if (modp->castIface()) {
// Track module depths, so can sort list from parent down to children
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
if (!nodep->cellp()) nodep->ifacep(modp->castIface());
} else if (modp->castNotFoundModule()) { // Will error out later
} else {
nodep->v3error("Non-interface used as an interface: "<<nodep->prettyName());
}
}
// Note cannot do modport resolution here; modports are allowed underneath generates
}
virtual void visit(AstPackageImport* nodep, AstNUser*) {
// Package Import: We need to do the package before the use of a package
nodep->iterateChildren(*this);
@@ -314,6 +334,23 @@ private:
}
}
}
if (nodep->modp()->castIface()) {
// Cell really is the parent's instantiation of an interface, not a normal module
// Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
// in the same way that a child does. Rename though to avoid conflict with cell.
// This is quite similar to how classes work; when unpacked classes are better supported
// may remap interfaces to be more like a class.
if (!nodep->hasIfaceVar()) {
string varName = nodep->name()+"__Viftop"; // V3LinkDot looks for this naming
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
idtypep->cellp(nodep); // Only set when real parent cell known
idtypep->ifacep(NULL); // cellp overrides
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
nodep->addNextHere(varp);
nodep->hasIfaceVar(true);
}
}
if (nodep->modp()) {
nodep->iterateChildren(*this);
}
+364 -47
View File
@@ -31,6 +31,26 @@
// VarXRef/Func's:
// Find appropriate named cell and link to var they reference
//*************************************************************************
// Interfaces:
// CELL (.port (ifref)
// ^--- cell -> IfaceDTypeRef(iface)
// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
// FindVisitor:
// #1: Insert interface Vars
// #2: Insert ModPort names
// IfaceVisitor:
// #3: Update ModPortVarRef to point at interface vars (after #1)
// #4: Create ModPortVarRef symbol table entries
// FindVisitor-insertIfaceRefs()
// #5: Resolve IfaceRefDtype modport names (after #2)
// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
// insertAllScopeAliases():
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
//*************************************************************************
// TOP
// {name-of-top-modulename}
// a (VSymEnt->AstCell)
@@ -77,17 +97,26 @@ private:
AstUser4InUse m_inuser4;
// TYPES
typedef std::multimap<string,VSymEnt*> NameScopeMap;
typedef set <pair<AstNodeModule*,string> > ImplicitNameSet;
typedef multimap<string,VSymEnt*> NameScopeSymMap;
typedef map<VSymEnt*,VSymEnt*> ScopeAliasMap;
typedef set<pair<AstNodeModule*,string> > ImplicitNameSet;
typedef vector<VSymEnt*> IfaceVarSyms;
typedef vector<pair<AstIface*,VSymEnt*> > IfaceModSyms;
static LinkDotState* s_errorThisp; // Last self, for error reporting only
// MEMBERS
VSymGraph m_syms; // Symbol table
VSymEnt* m_dunitEntp; // $unit entry
NameScopeMap m_nameScopeMap; // Hash of scope referenced by non-pretty textual name
NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it
ScopeAliasMap m_scopeAliasMap; // Map of <lhs,rhs> aliases
IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
bool m_forPrimary; // First link
bool m_forPrearray; // Compress cell__[array] refs
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
public:
static int debug() {
@@ -95,14 +124,27 @@ public:
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void dump() {
if (debug()>=6) m_syms.dumpFilePrefixed("linkdot");
void dump(const string& nameComment="linkdot", bool force=false) {
if (debug()>=6 || force) {
string filename = v3Global.debugFilename(nameComment)+".txt";
const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
ostream& os = *logp;
m_syms.dump(os);
if (!m_scopeAliasMap.empty()) os<<"\nScopeAliasMap:\n";
for (ScopeAliasMap::iterator it = m_scopeAliasMap.begin(); it != m_scopeAliasMap.end(); ++it) {
os<<"\t"<<it->first<<" -> "<<it->second<<endl;
}
}
}
static void preErrorDumpHandler() {
if (s_errorThisp) s_errorThisp->preErrorDump();
}
void preErrorDump() {
static bool diddump = false;
if (!diddump && v3Global.opt.dumpTree()) {
diddump = true;
m_syms.dumpFilePrefixed("linkdot-preerr");
dump("linkdot-preerr",true);
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
}
}
@@ -115,8 +157,13 @@ public:
m_forPrearray = (step == LDS_PARAMED || step==LDS_PRIMARY);
m_forScopeCreation = (step == LDS_SCOPED);
m_dunitEntp = NULL;
s_errorThisp = this;
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
}
~LinkDotState() {
V3Error::errorExitCb(NULL);
s_errorThisp = NULL;
}
~LinkDotState() {}
// ACCESSORS
VSymGraph* symsp() { return &m_syms; }
@@ -131,6 +178,7 @@ public:
else if (nodep->castTask()) return "task";
else if (nodep->castFunc()) return "function";
else if (nodep->castBegin()) return "block";
else if (nodep->castIface()) return "interface";
else return nodep->prettyTypeName();
}
static string ucfirst(const string& text) {
@@ -161,7 +209,6 @@ public:
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
} else {
preErrorDump();
UINFO(4,"name "<<name<<endl); // Not always same as nodep->name
UINFO(4,"Var1 "<<nodep<<endl);
UINFO(4,"Var2 "<<fnodep<<endl);
@@ -195,7 +242,7 @@ public:
nodep->user1p(symp);
checkDuplicate(rootEntp(), nodep, nodep->origName());
rootEntp()->insert(nodep->origName(),symp);
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp,
@@ -214,7 +261,7 @@ public:
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
modSymp->reinsert(nodep->name(), symp);
}
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp,
@@ -246,7 +293,7 @@ public:
UINFO(9," INSERTblk se"<<(void*)symp<<" above=se"<<(void*)abovep<<" node="<<nodep<<endl);
symp->parentp(abovep);
symp->packagep(packagep);
symp->fallbackp(abovep); // Needed so can find $unit stuff
symp->fallbackp(abovep);
nodep->user1p(symp);
if (name != "") {
checkDuplicate(abovep, nodep, name);
@@ -278,17 +325,17 @@ public:
return symp;
}
VSymEnt* getScopeSym(AstScope* nodep) {
NameScopeMap::iterator iter = m_nameScopeMap.find(nodep->name());
if (iter == m_nameScopeMap.end()) {
NameScopeSymMap::iterator it = m_nameScopeSymMap.find(nodep->name());
if (it == m_nameScopeSymMap.end()) {
nodep->v3fatalSrc("Scope never assigned a symbol entry?");
}
return iter->second;
return it->second;
}
void implicitOkAdd(AstNodeModule* nodep, const string& varname) {
// Mark the given variable name as being allowed to be implicitly declared
if (nodep) {
ImplicitNameSet::iterator iter = m_implicitNameSet.find(make_pair(nodep,varname));
if (iter == m_implicitNameSet.end()) {
ImplicitNameSet::iterator it = m_implicitNameSet.find(make_pair(nodep,varname));
if (it == m_implicitNameSet.end()) {
m_implicitNameSet.insert(make_pair(nodep,varname));
}
}
@@ -298,6 +345,69 @@ public:
&& (m_implicitNameSet.find(make_pair(nodep,varname)) != m_implicitNameSet.end());
}
// Track and later recurse interface modules
void insertIfaceModSym(AstIface* nodep, VSymEnt* symp) {
m_ifaceModSyms.push_back(make_pair(nodep, symp));
}
void computeIfaceModSyms();
// Track and later insert interface references
void insertIfaceVarSym(VSymEnt* symp) { // Where sym is for a VAR of dtype IFACEREFDTYPE
m_ifaceVarSyms.push_back(symp);
}
void computeIfaceVarSyms() {
for (IfaceVarSyms::iterator it = m_ifaceVarSyms.begin(); it != m_ifaceVarSyms.end(); ++it) {
VSymEnt* varSymp = *it;
AstVar* varp = varSymp->nodep()->castVar();
UINFO(9, " insAllIface se"<<(void*)varSymp<<" "<<varp<<endl);
AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType();
if (!ifacerefp) varp->v3fatalSrc("Non-ifacerefs on list!");
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
VSymEnt* ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp());
VSymEnt* ifOrPortSymp = ifaceSymp;
// Link Modport names to the Modport Node under the Interface
if (ifacerefp->isModport()) {
VSymEnt* foundp = ifaceSymp->findIdFallback(ifacerefp->modportName());
bool ok = false;
if (foundp) {
if (AstModport* modportp = foundp->nodep()->castModport()) {
UINFO(4,"Link Modport: "<<modportp<<endl);
ifacerefp->modportp(modportp);
ifOrPortSymp = foundp;
ok = true;
}
}
if (!ok) ifacerefp->v3error("Modport not found under interface '"
<<ifacerefp->prettyName(ifacerefp->ifaceName())
<<"': "<<ifacerefp->prettyName(ifacerefp->modportName()));
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias(varSymp, ifOrPortSymp);
}
m_ifaceVarSyms.clear();
}
// Track and later insert scope aliases
void insertScopeAlias(VSymEnt* lhsp, VSymEnt* rhsp) { // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
UINFO(9," insertScopeAlias se"<<(void*)lhsp<<" se"<<(void*)rhsp<<endl);
m_scopeAliasMap.insert(make_pair(lhsp, rhsp));
}
void computeScopeAliases() {
UINFO(9,"computeIfaceAliases\n");
for (ScopeAliasMap::iterator it=m_scopeAliasMap.begin(); it!=m_scopeAliasMap.end(); ++it) {
VSymEnt* lhsp = it->first;
VSymEnt* srcp = lhsp;
while (1) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap::iterator it2 = m_scopeAliasMap.find(srcp);
if (it2 != m_scopeAliasMap.end()) { srcp = it2->second; continue; }
else break;
}
UINFO(9," iiasa: Insert alias se"<<lhsp<<" <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
}
m_scopeAliasMap.clear();
}
private:
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
VSymEnt* findp = symp->findIdFallback(name);
@@ -399,10 +509,11 @@ public:
}
};
LinkDotState* LinkDotState::s_errorThisp = NULL;
//======================================================================
class LinkDotFindVisitor : public AstNVisitor {
private:
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstPackage* m_packagep; // Current package
@@ -486,6 +597,10 @@ private:
// Iterate
nodep->iterateChildren(*this);
nodep->user4(true);
// Interfaces need another pass when signals are resolved
if (AstIface* ifacep = nodep->castIface()) {
m_statep->insertIfaceModSym(ifacep, m_curSymp);
}
} else { //!doit
// Will be optimized away later
// Can't remove now, as our backwards iterator will throw up
@@ -525,7 +640,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp);
if (!aboveSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cell insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
}
@@ -554,7 +668,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp);
if (!aboveSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cellinline insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
m_statep->insertInline(aboveSymp, m_modSymp, nodep, ident);
@@ -666,7 +779,6 @@ private:
if (!foundp) {
ins=true;
} else if (!findvarp && foundp && m_curSymp->findIdFlat(nodep->name())) {
m_statep->preErrorDump();
nodep->v3error("Unsupported in C: Variable has same name as "
<<LinkDotState::nodeTextType(foundp->nodep())<<": "<<nodep->prettyName());
} else if (findvarp != nodep) {
@@ -705,12 +817,16 @@ private:
}
}
if (ins) {
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
if (m_statep->forPrimary() && nodep->isGParam()) {
m_paramNum++;
VSymEnt* symp = m_statep->insertSym(m_curSymp, "__paramNumber"+cvtToStr(m_paramNum), nodep, m_packagep);
symp->exported(false);
}
if (nodep->subDTypep()->castIfaceRefDType()) {
// Can't resolve until interfaces and modport names are known; see notes at top
m_statep->insertIfaceVarSym(insp);
}
}
}
}
@@ -763,7 +879,7 @@ private:
nodep->v3error("Import object not found: "<<nodep->packagep()->prettyName()<<"::"<<nodep->prettyName());
}
}
m_curSymp->import(m_statep->symsp(), srcp, nodep->name());
m_curSymp->importFromPackage(m_statep->symsp(), srcp, nodep->name());
UINFO(9," Link Done: "<<nodep<<endl);
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
@@ -885,8 +1001,8 @@ private:
AstVar* refp = foundp->nodep()->castVar();
if (!refp) {
nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName());
} else if (!refp->isIO()) {
nodep->v3error("Pin is not an in/out/inout: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout/interface: "<<nodep->prettyName());
} else {
refp->user4(true);
VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp),
@@ -942,9 +1058,10 @@ public:
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
private:
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstScope* m_scopep; // The current scope
VSymEnt* m_modSymp; // Symbol entry for current module
int debug() { return LinkDotState::debug(); }
@@ -960,12 +1077,36 @@ private:
// Using the CELL names, we created all hierarchy. We now need to match this Scope
// up with the hierarchy created by the CELL names.
m_modSymp = m_statep->getScopeSym(nodep);
m_scopep = nodep;
nodep->iterateChildren(*this);
m_modSymp = NULL;
m_scopep = NULL;
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
if (!nodep->varp()->isFuncLocal()) {
m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
if (nodep->varp()->isIfaceRef()
&& nodep->varp()->isIfaceParent()) {
UINFO(9,"Iface parent ref var "<<nodep->varp()->name()<<" "<<nodep<<endl);
// Find the interface cell the var references
AstIfaceRefDType* dtypep = nodep->varp()->dtypep()->castIfaceRefDType();
if (!dtypep) nodep->v3fatalSrc("Non AstIfaceRefDType on isIfaceRef() var");
UINFO(9,"Iface parent dtype "<<dtypep<<endl);
string ifcellname = dtypep->cellName();
string baddot; VSymEnt* okSymp;
VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!cellSymp) nodep->v3fatalSrc("No symbol for interface cell: " <<nodep->prettyName(ifcellname));
UINFO(5, " Found interface cell: se"<<(void*)cellSymp<<" "<<cellSymp->nodep()<<endl);
if (dtypep->modportName()!="") {
VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!mpSymp) { nodep->v3fatalSrc("No symbol for interface modport: " <<nodep->prettyName(dtypep->modportName())); }
else cellSymp = mpSymp;
UINFO(5, " Found modport cell: se"<<(void*)cellSymp<<" "<<mpSymp->nodep()<<endl);
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
m_statep->insertScopeAlias(varSymp, cellSymp);
}
}
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
@@ -976,15 +1117,44 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
if (m_statep->forScopeCreation()) {
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
fromVscp->user2p(toVscp);
}
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
fromVscp->user2p(toVscp);
nodep->iterateChildren(*this);
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
UINFO(5,"ASSIGNVARSCOPE "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\tavs: ");
VSymEnt* rhsSymp;
{
AstVarRef* refp = nodep->rhsp()->castVarRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarRef attached to interface pin");
string scopename = refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias rhs");
UINFO(5, " Found a linked scope RHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
rhsSymp = symp;
}
VSymEnt* lhsSymp;
{
AstVarXRef* refp = nodep->lhsp()->castVarXRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarXRef attached to interface pin");
string scopename = refp->dotted()+"."+refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias lhs");
UINFO(5, " Found a linked scope LHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
lhsSymp = symp;
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
m_statep->insertScopeAlias(lhsSymp, rhsSymp);
// We have stored the link, we don't need these any more
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
// For speed, don't recurse things that can't have scope
// Note we allow AstNodeStmt's as generates may be under them
virtual void visit(AstCell*, AstNUser*) {}
@@ -1000,6 +1170,7 @@ public:
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_modSymp = NULL;
m_scopep = NULL;
m_statep = statep;
//
rootp->accept(*this);
@@ -1009,6 +1180,78 @@ public:
//======================================================================
// Iterate an interface to resolve modports
class LinkDotIfaceVisitor : public AstNVisitor {
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
// METHODS
int debug() { return LinkDotState::debug(); }
// VISITs
virtual void visit(AstModport* nodep, AstNUser*) {
// Modport: Remember its name for later resolution
UINFO(5," fiv: "<<nodep<<endl);
VSymEnt* oldCurSymp = m_curSymp;
{
// Create symbol table for the vars
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, NULL);
m_curSymp->fallbackp(oldCurSymp);
nodep->iterateChildren(*this);
}
m_curSymp = oldCurSymp;
}
virtual void visit(AstModportVarRef* nodep, AstNUser*) {
UINFO(5," fiv: "<<nodep<<endl);
nodep->iterateChildren(*this);
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
if (!symp) {
nodep->v3error("Modport item not found: "<<nodep->prettyName());
} else if (AstVar* varp = symp->nodep()->castVar()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(varp);
m_statep->insertSym(m_curSymp, nodep->name(), varp, NULL/*package*/);
} else if (AstVarScope* vscp = symp->nodep()->castVarScope()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(vscp->varp());
m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL/*package*/);
} else {
nodep->v3error("Modport item is not a variable: "<<nodep->prettyName());
}
if (m_statep->forScopeCreation()) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_curSymp = curSymp;
m_statep = statep;
nodep->accept(*this);
}
virtual ~LinkDotIfaceVisitor() {}
};
void LinkDotState::computeIfaceModSyms() {
for (IfaceModSyms::iterator it=m_ifaceModSyms.begin(); it!=m_ifaceModSyms.end(); ++it) {
AstIface* nodep = it->first;
VSymEnt* symp = it->second;
LinkDotIfaceVisitor(nodep, symp, this);
}
m_ifaceModSyms.clear();
}
//======================================================================
class LinkDotResolveVisitor : public AstNVisitor {
private:
// NODE STATE
@@ -1037,6 +1280,7 @@ private:
AstCell* m_cellp; // Current cell
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
int m_modportNum; // Uniqueify modport numbers
struct DotStates {
DotPosition m_dotPos; // Scope part of dotted resolution
@@ -1087,12 +1331,21 @@ private:
}
inline void checkNoDot(AstNode* nodep) {
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
m_statep->preErrorDump();
UINFO(1,"ds="<<m_ds.ascii()<<endl);
//UINFO(9,"ds="<<m_ds.ascii()<<endl);
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type()<<" in dotted expression");
m_ds.m_dotErr = true;
}
}
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, AstModport* modportp) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep->name()+"__Vmp__"+modportp->name()+"__Viftop"+cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, cellp->name(), ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
}
// VISITs
virtual void visit(AstNetlist* nodep, AstNUser* vup) {
@@ -1108,6 +1361,7 @@ private:
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
m_cellp = NULL;
m_modp = nodep;
m_modportNum = 0;
nodep->iterateChildren(*this);
m_modp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
@@ -1130,7 +1384,7 @@ private:
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
// Cell: Recurse inside or cleanup not founds
checkNoDot(nodep);
m_cellp = nodep;
AstNode::user5ClearTree();
@@ -1172,8 +1426,8 @@ private:
return;
}
nodep->v3error("Pin not found: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam()) {
nodep->v3error("Pin is not an in/out/inout/param: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout/param/interface: "<<nodep->prettyName());
} else {
nodep->modVarp(refp);
if (refp->user5p() && refp->user5p()->castNode()!=nodep) {
@@ -1212,10 +1466,12 @@ private:
} else {
m_ds.m_dotPos = DP_SCOPE;
nodep->lhsp()->iterateAndNext(*this);
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
}
if (!m_ds.m_dotErr) { // Once something wrong, give up
if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
nodep->rhsp()->iterateAndNext(*this);
//if (debug()>=9) nodep->dumpTree("-dot-rho: ");
}
if (start) {
AstNode* newp;
@@ -1299,7 +1555,8 @@ private:
} else {
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
}
if (foundp) UINFO(9," found=se"<<(void*)foundp<<" n="<<foundp->nodep()<<endl);
if (foundp) UINFO(9," found=se"<<(void*)foundp<<" exp="<<expectWhat
<<" n="<<foundp->nodep()<<endl);
// What fell out?
bool ok = false;
if (foundp->nodep()->castCell() || foundp->nodep()->castBegin()
@@ -1312,9 +1569,41 @@ private:
m_ds.m_dotPos = DP_SCOPE;
// Upper AstDot visitor will handle it from here
}
else if (foundp->nodep()->castCell()
&& allowVar && m_cellp
&& foundp->nodep()->castCell()->modp()->castIface()) {
// Interfaces can be referenced like a variable for interconnect
AstCell* cellp = foundp->nodep()->castCell();
VSymEnt* cellEntp = m_statep->getNodeSym(cellp); if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or generate begin
string findName = nodep->name()+"__Viftop";
AstVar* ifaceRefVarp = parentEntp->findIdFallback(findName)->nodep()->castVar();
if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<<findName);
//
ok = true;
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
AstNode* newp = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
}
else if (AstVar* varp = foundp->nodep()->castVar()) {
if (allowVar) {
if (AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType()) {
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
// Really this is a scope reference into an interface
UINFO(9,"varref-ifaceref "<<m_ds.m_dotText<<" "<<nodep<<endl);
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
else if (allowVar) {
AstNodeVarRef* newp;
if (m_ds.m_dotText != "") {
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
@@ -1331,6 +1620,34 @@ private:
ok = true;
}
}
else if (AstModport* modportp = foundp->nodep()->castModport()) {
// A scope reference into an interface's modport (not necessarily at a pin connection)
UINFO(9,"cell-ref-to-modport "<<m_ds.m_dotText<<" "<<nodep<<endl);
UINFO(9,"dotSymp "<<m_ds.m_dotSymp<<" "<<m_ds.m_dotSymp->nodep()<<endl);
// Iface was the previously dotted component
if (!m_ds.m_dotSymp
|| !m_ds.m_dotSymp->nodep()->castCell()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced as <interface>."<<modportp->prettyName());
} else if (!m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced from underneath an interface: "<<modportp->prettyName());
} else {
AstCell* cellp = m_ds.m_dotSymp->nodep()->castCell();
if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell");
AstIface* ifacep = cellp->modp()->castIface();
//string cellName = m_ds.m_dotText; // Use cellp->name
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
}
}
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
if (allowVar) {
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
@@ -1344,7 +1661,6 @@ private:
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="");
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
if (err) {
m_statep->preErrorDump();
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
<<"'"<<" as a "<<foundp->nodep()->typeName()
@@ -1388,7 +1704,6 @@ private:
nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import
}
if (!nodep->varp()) {
m_statep->preErrorDump();
nodep->v3error("Can't find definition of signal, again: "<<nodep->prettyName());
}
}
@@ -1412,7 +1727,6 @@ private:
string inl = AstNode::dedotName(nodep->inlinedDots());
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
}
@@ -1423,7 +1737,6 @@ private:
nodep->varp(varp);
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp
if (!nodep->varp()) {
m_statep->preErrorDump();
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
}
@@ -1432,7 +1745,6 @@ private:
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVarScope* vscp = foundp->nodep()->castVarScope(); // maybe NULL
if (!vscp) {
m_statep->preErrorDump();
nodep->v3error("Can't find varpin scope of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
} else {
@@ -1499,7 +1811,6 @@ private:
UINFO(8,"\t\tInlined "<<inl<<endl);
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
m_statep->preErrorDump();
okSymp->cellErrorScopes(nodep);
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
@@ -1516,7 +1827,6 @@ private:
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
} else {
// Note ParseRef has similar error handling/message output
m_statep->preErrorDump();
UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl);
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
@@ -1670,6 +1980,7 @@ public:
m_cellp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
m_modportNum = 0;
//
rootp->accept(*this);
}
@@ -1691,12 +2002,18 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
LinkDotParamVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
}
else if (step == LDS_ARRAYED) {}
else if (step == LDS_SCOPED) {
// Well after the initial link when we're ready to operate on the flat design,
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
LinkDotScopeVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
}
else v3fatalSrc("Bad case");
state.dump();
state.computeIfaceModSyms();
state.computeIfaceVarSyms();
state.computeScopeAliases();
state.dump();
LinkDotResolveVisitor visitorb(rootp,&state);
}
+19 -4
View File
@@ -67,9 +67,11 @@ void V3LinkLevel::modSortByLevel() {
}
vec.push_back(nodep);
}
sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
stable_sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
for (ModVec::iterator it = vec.begin(); it != vec.end(); ++it) {
AstNodeModule* nodep = *it;
nodep->clearIter(); // Because we didn't iterate to find the node pointers, may have a stale m_iterp() needing cleanup
nodep->unlinkFrBack();
}
if (v3Global.rootp()->modulesp()) v3Global.rootp()->v3fatalSrc("Unlink didn't work");
@@ -77,6 +79,7 @@ void V3LinkLevel::modSortByLevel() {
AstNodeModule* nodep = *it;
v3Global.rootp()->addModulep(nodep);
}
UINFO(9,"modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
}
//######################################################################
@@ -95,6 +98,18 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
newmodp->modPublic(true);
netlistp->addModulep(newmodp);
// TODO the module creation above could be done after linkcells, but
// the rest must be done after data type resolution
wrapTopCell(netlistp);
wrapTopPackages(netlistp);
}
void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
AstNodeModule* newmodp = netlistp->modulesp();
if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
AstNodeModule* oldmodp = newmodp->nextp()->castNodeModule();
if (!oldmodp) netlistp->v3fatalSrc("No module found to process");
// Add instance
AstCell* cellp = new AstCell(newmodp->fileline(),
(v3Global.opt.l2Name() ? "v" : oldmodp->name()),
@@ -126,13 +141,13 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
}
}
}
wrapTopPackages(netlistp, newmodp);
}
void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp, AstNodeModule* newmodp) {
void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp) {
// Instantiate all packages under the top wrapper
// This way all later SCOPE based optimizations can ignore packages
AstNodeModule* newmodp = netlistp->modulesp();
if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
for (AstNodeModule* modp = netlistp->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
if (modp->castPackage()) {
AstCell* cellp = new AstCell(modp->fileline(),
+2 -1
View File
@@ -29,7 +29,8 @@
class V3LinkLevel {
private:
static void wrapTopPackages(AstNetlist* nodep, AstNodeModule* newmodp);
static void wrapTopCell(AstNetlist* nodep);
static void wrapTopPackages(AstNetlist* nodep);
public:
static void modSortByLevel();
static void wrapTop(AstNetlist* nodep);
+6
View File
@@ -152,6 +152,12 @@ private:
nodep->valuep()->unlinkFrBack()));
}
}
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
// Only AstIfaceRefDType's at this point correspond to ports;
// haven't made additional ones for interconnect yet, so assert is simple
// What breaks later is we don't have a Scope/Cell representing the interface to attach to
if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
}
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
+1 -1
View File
@@ -515,7 +515,7 @@ uint32_t V3Number::toUInt() const {
double V3Number::toDouble() const {
if (VL_UNLIKELY(!isDouble())) {
m_fileline->v3fatalSrc("Real conversion on non real number");
m_fileline->v3fatalSrc("Real conversion on non-real number");
}
if (VL_UNLIKELY(width()!=64)) {
m_fileline->v3fatalSrc("Real operation on wrong sized number");
+10 -3
View File
@@ -46,7 +46,8 @@
//######################################################################
// V3 Internal state
struct V3OptionsImp {
class V3OptionsImp {
public:
// TYPES
typedef std::map<string,set<string> > DirMap; // Directory listing
@@ -91,6 +92,7 @@ struct V3OptionsImp {
}
}
V3OptionsImp() {}
~V3OptionsImp() {}
};
void V3Options::addIncDirUser(const string& incdir) {
@@ -736,6 +738,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-l2name", flag/*ref*/) ) { m_l2Name = flag; }
else if ( onoff (sw, "-lint-only", flag/*ref*/) ) { m_lintOnly = flag; }
else if ( !strcmp (sw, "-no-pins64") ) { m_pinsBv = 33; }
else if ( onoff (sw, "-order-clock-delay", flag/*ref*/) ) { m_orderClockDly = flag; }
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; }
@@ -960,7 +963,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
}
else if ( !strcmp (sw, "-compiler") && (i+1)<argc) {
shift;
if (!strcmp (argv[i], "gcc")) {
if (!strcmp (argv[i], "clang")) {
m_compLimitParens = 80; // limit unknown
m_compLimitBlocks = 80; // limit unknown
} else if (!strcmp (argv[i], "gcc")) {
m_compLimitParens = 0;
} else if (!strcmp (argv[i], "msvc")) {
m_compLimitParens = 80; // 128, but allow some room
@@ -1201,6 +1207,7 @@ V3Options::V3Options() {
m_lintOnly = false;
m_makeDepend = true;
m_makePhony = false;
m_orderClockDly = true;
m_outFormatOk = false;
m_warnFatal = true;
m_pinsBv = 65;
@@ -1307,7 +1314,7 @@ void V3Options::optimize(int level) {
m_oSubst = flag;
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = level >= 3;
m_oDedupe = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+2
View File
@@ -74,6 +74,7 @@ class V3Options {
bool m_inhibitSim; // main switch: --inhibit-sim
bool m_l2Name; // main switch: --l2name
bool m_lintOnly; // main switch: --lint-only
bool m_orderClockDly;// main switch: --order-clock-delay
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
@@ -214,6 +215,7 @@ class V3Options {
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool traceUnderscore() const { return m_traceUnderscore; }
bool orderClockDly() const { return m_orderClockDly; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool warnFatal() const { return m_warnFatal; }
+30 -8
View File
@@ -476,7 +476,7 @@ private:
// elements. Up to 10 of the widest
cerr<<V3Error::msgPrefix()
<<" Widest candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
std::stable_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];
@@ -489,8 +489,8 @@ private:
// 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());
std::stable_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];
@@ -697,6 +697,13 @@ private:
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
if (m_inPost) {
new OrderPostCutEdge(&m_graph, m_logicVxp, varVxp);
// Mark the vertex. Used to control marking
// internal clocks circular, which must only
// happen if they are generated by delayed
// assignment.
UINFO(5, " Found delayed assignment (post) "
<< varVxp << endl);
varVxp->isDelayed(true);
} else {
new OrderComboCutEdge(&m_graph, m_logicVxp, varVxp);
}
@@ -1146,10 +1153,25 @@ void OrderVisitor::processCircular() {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(itp)) {
if (vvertexp->isClock() && !vvertexp->isFromInput()) {
// If a clock is generated internally, we need to do another loop
// through the entire evaluation. This fixes races; see t_clk_dpulse test.
UINFO(5,"Circular Clock "<<vvertexp<<endl);
nodeMarkCircular(vvertexp, NULL);
// If a clock is generated internally, we need to do another
// loop through the entire evaluation. This fixes races; see
// t_clk_dpulse test.
//
// This all seems to hinge on how the clock is generated. If
// it is generated by delayed assignment, we need the loop. If
// it is combinatorial, we do not (and indeed it will break
// other tests such as t_gated_clk_1.
if (!v3Global.opt.orderClockDly()) {
UINFO(5,"Circular Clock, no-order-clock-delay "<<vvertexp<<endl);
nodeMarkCircular(vvertexp, NULL);
}
else if (vvertexp->isDelayed()) {
UINFO(5,"Circular Clock, delayed "<<vvertexp<<endl);
nodeMarkCircular(vvertexp, NULL);
}
else {
UINFO(5,"Circular Clock, not delayed "<<vvertexp<<endl);
}
}
// Also mark any cut edges
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
@@ -1324,7 +1346,7 @@ void OrderVisitor::processEdgeReport() {
}
*logp<<"Signals and their clock domains:"<<endl;
sort(report.begin(), report.end());
stable_sort(report.begin(), report.end());
for (deque<string>::iterator it=report.begin(); it!=report.end(); ++it) {
*logp<<(*it)<<endl;
}
+4 -1
View File
@@ -224,6 +224,7 @@ class OrderVarVertex : public OrderEitherVertex {
AstVarScope* m_varScp;
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
bool m_isClock; // Used as clock
bool m_isDelayed; // Set in a delayed assignment
protected:
OrderVarVertex(V3Graph* graphp, const OrderVarVertex& old)
: OrderEitherVertex(graphp, old)
@@ -231,7 +232,7 @@ protected:
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), m_isDelayed(false) {}
virtual ~OrderVarVertex() {}
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
virtual OrderVEdgeType type() const = 0;
@@ -239,6 +240,8 @@ public:
AstVarScope* varScp() const { return m_varScp; }
void isClock(bool flag) { m_isClock=flag; }
bool isClock() const { return m_isClock; }
void isDelayed(bool flag) { m_isDelayed=flag; }
bool isDelayed() const { return m_isDelayed; }
OrderVarVertex* pilNewVertexp() const { return m_pilNewVertexp; }
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
};
+123 -18
View File
@@ -21,13 +21,31 @@
// Top down traversal:
// For each cell:
// If parameterized,
// Determine all parameter widths, constant values
// Determine all parameter widths, constant values.
// (Interfaces also matter, as if an interface is parameterized
// this effectively changes the width behavior of all that
// reference the iface.)
// Clone module cell calls, renaming with __{par1}_{par2}_...
// Substitute constants for cell's module's parameters
// Relink pins and cell to point to new module
// Then process all modules called by that cell
// Substitute constants for cell's module's parameters.
// Relink pins and cell and ifacerefdtype to point to new module.
//
// For interface Parent's we have the AstIfaceRefDType::cellp()
// pointing to this module. If that parent cell's interface
// module gets parameterized, AstIfaceRefDType::cloneRelink
// will update AstIfaceRefDType::cellp(), and AstLinkDot will
// see the new interface.
//
// However if a submodule's AstIfaceRefDType::ifacep() points
// to the old (unparameterized) interface and needs correction.
// To detect this we must walk all pins looking for interfaces
// that the parent has changed and propagate down.
//
// Then process all modules called by that cell.
// (Cells never referenced after parameters expanded must be ignored.)
//
// After we complete parameters, the varp's will be wrong (point to old module)
// and must be relinked.
//
//*************************************************************************
#include "config_build.h"
@@ -62,23 +80,34 @@ private:
AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations
// TYPES
typedef deque<pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
// STATE
typedef std::map<AstVar*,AstVar*> VarCloneMap;
typedef map<AstVar*,AstVar*> VarCloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp
ModInfo(AstNodeModule* modp) { m_modp=modp; }
};
typedef std::map<string,ModInfo> ModNameMap;
typedef map<string,ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string,string> LongMap;
typedef map<string,string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
typedef map<AstNode*,int> ValueMap;
typedef map<int,int> NextValueMap;
ValueMap m_valueMap; // Hash of node to param value
NextValueMap m_nextValueMap;// Hash of param value to next value to be used
typedef multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
typedef deque<AstCell*> CellList;
CellList m_cellps; // Cells left to process (in this module)
// METHODS
static int debug() {
static int level = -1;
@@ -91,7 +120,7 @@ private:
// Pass 1, assign first letter to each gparam's name
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
if (varp->isGParam()) {
if (varp->isGParam()||varp->isIfaceRef()) {
char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
@@ -113,6 +142,27 @@ private:
}
return st;
}
string paramValueNumber(AstNode* nodep) {
// Given a compilcated object create a number to use for param module assignment
// Ideally would be relatively stable if design changes (not use pointer value),
// and must return same value given same input node
// Return must presently be numberic so doesn't collide with 'small' alphanumeric parameter names
ValueMap::iterator it = m_valueMap.find(nodep);
if (it != m_valueMap.end()) {
return cvtToStr(it->second);
} else {
static int BUCKETS = 1000;
V3Hash hash (nodep->name());
int bucket = hash.hshval() % BUCKETS;
int offset = 0;
NextValueMap::iterator it = m_nextValueMap.find(bucket);
if (it != m_nextValueMap.end()) { offset = it->second; it->second = offset + 1; }
else { m_nextValueMap.insert(make_pair(bucket, offset + 1)); }
int num = bucket + offset * BUCKETS;
m_valueMap.insert(make_pair(nodep, num));
return cvtToStr(num);
}
}
void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) {
for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n");
@@ -123,9 +173,10 @@ private:
pinp->modVarp(cloneiter->second);
}
}
void visitCell(AstCell* nodep);
void visitModules() {
// Loop on all modules left to process
// Hitting a cell adds to the appropriate leval of this level-sorted list,
// Hitting a cell adds to the appropriate level of this level-sorted list,
// so since cells originally exist top->bottom we process in top->bottom order too.
while (!m_todoModps.empty()) {
LevelModMap::iterator it = m_todoModps.begin();
@@ -134,7 +185,19 @@ private:
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
UINFO(4," MOD "<<nodep<<endl);
nodep->iterateChildren(*this);
// Note this may add to m_todoModps
// Note above iterate may add to m_todoModps
//
// Process interface cells, then non-interface which may ref an interface cell
for (int nonIf=0; nonIf<2; ++nonIf) {
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
AstCell* nodep = *it;
if ((nonIf==0 && nodep->modp()->castIface())
|| (nonIf==1 && !nodep->modp()->castIface())) {
visitCell(nodep);
}
}
}
m_cellps.clear();
}
}
}
@@ -157,7 +220,10 @@ private:
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
}
}
virtual void visit(AstCell* nodep, AstNUser*);
virtual void visit(AstCell* nodep, AstNUser*) {
// Must do ifaces first, so push to list and do in proper order
m_cellps.push_back(nodep);
}
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
@@ -218,7 +284,7 @@ private:
//! Parameter subsitution for generated for loops.
//! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional
//! expression, since this is currently restricted to simple comparisons. If we ever do
//! move to more generic constant expressions, such code will be neede here.
//! move to more generic constant expressions, such code will be needed here.
virtual void visit(AstBegin* nodep, AstNUser*) {
if (nodep->genforp()) {
AstGenFor* forp = nodep->genforp()->castGenFor();
@@ -317,11 +383,13 @@ public:
//----------------------------------------------------------------------
// VISITs
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
void ParamVisitor::visitCell(AstCell* nodep) {
// Cell: Check for parameters in the instantiation.
nodep->iterateChildren(*this);
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
if (nodep->paramsp()) {
if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
if (nodep->paramsp()
|| 1 // Need to look for interfaces; could track when one exists, but should be harmless to always do this
) {
UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants
if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
@@ -336,7 +404,6 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
longname += "_";
if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t");
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp) nodep->v3fatalSrc("Non pin under cell params\n");
if (!pinp->exprp()) continue; // No-connect
AstVar* modvarp = pinp->modVarp();
if (!modvarp) {
@@ -360,6 +427,30 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
}
}
}
IfaceRefRefs ifaceRefRefs;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp->isIfaceRef()) {
AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
//UINFO(9," portIfaceRef "<<portIrefp<<endl);
if (!pinp->exprp()
|| !pinp->exprp()->castVarRef()
|| !pinp->exprp()->castVarRef()->varp()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
} else {
AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
//UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
any_overrides = true;
ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
}
}
}
}
if (!any_overrides) {
UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
@@ -402,7 +493,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Note we allow multiple users of a parameterized model, thus we need to stash this info.
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
if (varp->isIO() || varp->isGParam()) {
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
// Cloning saved a pointer to the new node for us, so just follow that link.
AstVar* oldvarp = varp->clonep()->castVar();
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
@@ -414,7 +505,21 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Relink parameter vars to the new module
relinkPins(clonemapp, nodep->paramsp());
// Fix any interface references
for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
AstIfaceRefDType* portIrefp = it->first;
AstIfaceRefDType* pinIrefp = it->second;
AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
UINFO(8," IfaceOld "<<portIrefp<<endl);
UINFO(8," IfaceTo "<<pinIrefp<<endl);
if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
UINFO(8," IfaceClo "<<cloneIrefp<<endl);
cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
UINFO(8," IfaceNew "<<cloneIrefp<<endl);
}
// Assign parameters to the constants specified
// DOES clone() so must be finished with module clonep() before here
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp && pinp->exprp()) {
@@ -440,7 +545,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
} // if any_overrides
// Delete the parameters from the cell; they're not relevant any longer.
nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
}
+1
View File
@@ -66,6 +66,7 @@ struct V3ParseBisonYYSType {
AstCell* cellp;
AstConst* constp;
AstMemberDType* memberp;
AstModportVarRef* modportvarrefp;
AstNodeModule* modulep;
AstNodeClassDType* classp;
AstNodeDType* dtypep;
+1 -1
View File
@@ -128,7 +128,7 @@ public:
}
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
symCurrentp()->import(&m_syms, symp, id_or_star);
symCurrentp()->importFromPackage(&m_syms, symp, id_or_star);
}
public:
// CREATORS
+2 -1
View File
@@ -107,7 +107,8 @@ public:
//*************************************************************************
// Data for a preprocessor instantiation.
struct V3PreProcImp : public V3PreProc {
class V3PreProcImp : public V3PreProc {
public:
// TYPES
typedef std::map<string,V3Define> DefinesMap;
typedef V3InFilter::StrList StrList;
+22 -6
View File
@@ -150,6 +150,14 @@ private:
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Copy under the scope but don't recurse
UINFO(4," Move "<<nodep<<endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
@@ -215,12 +223,17 @@ private:
virtual void visit(AstVarRef* nodep, AstNUser*) {
// VarRef needs to point to VarScope
// Make sure variable has made user1p.
nodep->varp()->accept(*this);
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
if (!nodep->varp()) nodep->v3fatalSrc("Unlinked");
if (nodep->varp()->isIfaceRef()) {
nodep->varScopep(NULL);
} else {
nodep->varp()->accept(*this);
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
}
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
@@ -298,6 +311,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
+12 -7
View File
@@ -431,11 +431,11 @@ private:
if (jumpingOver(nodep)) return;
if (!optimizable()) return; // Accelerate
if (nodep->castAssignDly()) {
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non-dly assigns");
m_anyAssignDly = true;
m_inDlyAssign = true;
} else {
if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non dly assigns");
if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non-dly assigns");
m_anyAssignComb = true;
}
if (!nodep->lhsp()->castVarRef()) {
@@ -603,20 +603,25 @@ private:
if (m_params) { V3Width::widthParamsEdit(funcp); } funcp=NULL; // Make sure we've sized the function
funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
// Apply function call values to function
// Note we'd need a stack if we allowed recursive functions!
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
// Must do this in two steps, eval all params, then apply them
// Otherwise chained functions may have the wrong results
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second;
if (pinp==NULL) {
// Too few arguments in function call - ignore it
} else {
AstNode* pinp = it->second->exprp();
if (pinp) { // Else too few arguments in function call - ignore it
if (portp->isOutput()) {
clearOptimizable(portp,"Language violation: Outputs not allowed in constant functions");
return;
}
// Evaluate pin value
pinp->accept(*this);
}
}
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second->exprp();
if (pinp) { // Else too few arguments in function call - ignore it
// Apply value to the function
if (!m_checkOnly && optimizable()) {
newNumber(portp)->opAssign(*fetchNumber(pinp));
+17 -5
View File
@@ -137,11 +137,11 @@ public:
VSymEnt* findIdFlat(const string& name) const {
// Find identifier without looking upward through symbol hierarchy
// First, scan this begin/end block or module for the name
IdNameMap::const_iterator iter = m_idNameMap.find(name);
IdNameMap::const_iterator it = m_idNameMap.find(name);
UINFO(9, " SymFind se"<<(void*)this<<" '"<<name
<<"' -> "<<(iter == m_idNameMap.end() ? "NONE"
: "se"+cvtToStr((void*)(iter->second))+" n="+cvtToStr((void*)(iter->second->nodep())))<<endl);
if (iter != m_idNameMap.end()) return (iter->second);
<<"' -> "<<(it == m_idNameMap.end() ? "NONE"
: "se"+cvtToStr((void*)(it->second))+" n="+cvtToStr((void*)(it->second->nodep())))<<endl);
if (it != m_idNameMap.end()) return (it->second);
return NULL;
}
VSymEnt* findIdFallback(const string& name) const {
@@ -166,7 +166,7 @@ private:
}
}
public:
bool import(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
bool importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
// Import tokens from source symbol table into this symbol table
// Returns true if successful
bool any = false;
@@ -183,6 +183,18 @@ public:
}
return any;
}
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
// Import interface tokens from source symbol table into this symbol table, recursively
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first;
VSymEnt* srcp = it->second;
VSymEnt* symp = new VSymEnt(graphp, srcp);
reinsert(name, symp);
// And recurse to create children
srcp->importFromIface(graphp, symp);
}
}
void cellErrorScopes(AstNode* lookp, string prettyName="") {
if (prettyName=="") prettyName = lookp->prettyName();
string scopes;
+90 -24
View File
@@ -370,7 +370,8 @@ private:
V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
portp->unlinkFrBack(); pushDeletep(portp); // Remove it from the clone (not original)
if (pinp==NULL) {
// Too few arguments in function call
@@ -378,6 +379,7 @@ private:
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
pinp->unlinkFrBack(); // Relinked to assignment below
argp->unlinkFrBack()->deleteTree(); // Args no longer needed
//
if ((portp->isInout()||portp->isOutput()) && pinp->castConst()) {
pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName());
@@ -476,7 +478,7 @@ private:
V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second;
AstNode* pinp = it->second->exprp();
if (!pinp) {
// Too few arguments in function call
} else {
@@ -532,9 +534,10 @@ private:
AstNode* nextpinp;
for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) {
nextpinp = pinp->nextp();
// Move pin to the CCall
pinp->unlinkFrBack();
ccallp->addArgsp(pinp);
// Move pin to the CCall, removing all Arg's
AstNode* exprp = pinp->castArg()->exprp();
exprp->unlinkFrBack();
ccallp->addArgsp(exprp);
}
if (outvscp) {
@@ -1177,20 +1180,20 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Missing pin/expr? We return (pinvar, NULL)
// Extra pin/expr? We clean it up
typedef map<string,int> NameToIndex;
NameToIndex nameToIndex;
V3TaskConnects tconnects;
if (!nodep->taskp()) nodep->v3fatalSrc("unlinked");
// Find ports
//map<string,int> name_to_pinnum;
int tpinnum = 0; // Note grammar starts pin counting at one
int tpinnum = 0;
AstVar* sformatp = NULL;
for (AstNode* stmtp = taskStmtsp; stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) {
tconnects.push_back(make_pair(portp, (AstNode*)NULL));
// Eventually we'll do name based connections
// That'll require a AstTpin or somesuch which will replace the ppinnum counting
//name_to_pinnum.insert(make_pair(portp->name(), tpinnum));
tconnects.push_back(make_pair(portp, (AstArg*)NULL));
nameToIndex.insert(make_pair(portp->name(), tpinnum)); // For name based connections
tpinnum++;
if (portp->attrSFormat()) {
sformatp = portp;
@@ -1201,27 +1204,90 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
}
}
// Connect pins
// Find pins
int ppinnum = 0;
for (AstNode* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()) {
if (ppinnum >= tpinnum) {
if (sformatp) {
tconnects.push_back(make_pair(sformatp, (AstNode*)NULL));
bool reorganize = false;
for (AstNode* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
nextp = pinp->nextp();
AstArg* argp = pinp->castArg(); if (!argp) pinp->v3fatalSrc("Non-arg under ftask reference");
if (argp->name() != "") {
// By name
NameToIndex::iterator it = nameToIndex.find(argp->name());
if (it == nameToIndex.end()) {
pinp->v3error("No such argument '"<<argp->prettyName()
<<"' in function call to "<<nodep->taskp()->prettyTypeName());
// We'll just delete it; seems less error prone than making a false argument
pinp->unlinkFrBack()->deleteTree(); pinp=NULL;
} else {
pinp->v3error("Too many arguments in function call to "<<nodep->taskp()->prettyTypeName());
// We'll just delete them; seems less error prone than making a false argument
pinp->unlinkFrBackWithNext()->deleteTree(); pinp=NULL;
break;
if (tconnects[it->second].second) {
pinp->v3error("Duplicate argument '"<<argp->prettyName()
<<"' in function call to "<<nodep->taskp()->prettyTypeName());
}
argp->name(""); // Can forget name as will add back in pin order
tconnects[it->second].second = argp;
reorganize = true;
}
} else { // By pin number
if (ppinnum >= tpinnum) {
if (sformatp) {
tconnects.push_back(make_pair(sformatp, (AstArg*)NULL));
tconnects[ppinnum].second = argp;
tpinnum++;
} else {
pinp->v3error("Too many arguments in function call to "<<nodep->taskp()->prettyTypeName());
// We'll just delete it; seems less error prone than making a false argument
pinp->unlinkFrBack()->deleteTree(); pinp=NULL;
}
} else {
tconnects[ppinnum].second = argp;
}
}
tconnects[ppinnum].second = pinp;
ppinnum++;
}
while (ppinnum < tpinnum) {
nodep->v3error("Too few arguments in function call to "<<nodep->taskp()->prettyTypeName());
UINFO(1,"missing argument for '"<<tconnects[ppinnum].first->prettyName()<<"'"<<endl);
ppinnum++;
// Connect missing ones
for (int i=0; i<tpinnum; ++i) {
AstVar* portp = tconnects[i].first;
if (!tconnects[i].second || !tconnects[i].second->exprp()) {
AstNode* newvaluep = NULL;
if (!portp->valuep()) {
nodep->v3error("Missing argument on non-defaulted argument '"<<portp->prettyName()
<<"' in function call to "<<nodep->taskp()->prettyTypeName());
newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0);
} else if (!portp->valuep()->castConst()) {
// Problem otherwise is we might have a varref, task call, or something else that only
// makes sense in the domain of the function, not the callee.
nodep->v3error("Unsupported: Non-constant default value in missing argument '"<<portp->prettyName()
<<"' in function call to "<<nodep->taskp()->prettyTypeName());
newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0);
} else {
newvaluep = portp->valuep()->cloneTree(true);
}
// To avoid problems with callee needing to know to deleteTree or not, we make this into a pin
UINFO(9,"Default pin for "<<portp<<endl);
AstArg* newp = new AstArg(nodep->fileline(), portp->name(), newvaluep);
if (tconnects[i].second) { // Have a "NULL" pin already defined for it
tconnects[i].second->unlinkFrBack()->deleteTree(); tconnects[i].second=NULL;
}
tconnects[i].second = newp;
reorganize = true;
}
if (tconnects[i].second) { UINFO(9,"Connect "<<portp<<" -> "<<tconnects[i].second<<endl); }
else { UINFO(9,"Connect "<<portp<<" -> NONE"<<endl); }
}
if (reorganize) {
// To simplify downstream, put argument list back into pure pinnumber ordering
while (nodep->pinsp()) nodep->pinsp()->unlinkFrBack(); // Must unlink each pin, not all pins linked together as one list
for (int i=0; i<tpinnum; ++i) {
AstArg* argp = tconnects[i].second; if (!argp) nodep->v3fatalSrc("Lost argument in func conversion");
nodep->addPinsp(argp);
}
}
if (debug()>=9) {
nodep->dumpTree(cout,"-ftref-out: ");
for (int i=0; i<tpinnum; ++i) UINFO(0," pin "<<i<<" conn="<<(void*)tconnects[i].second<<endl);
}
return tconnects;
}
+1 -1
View File
@@ -28,7 +28,7 @@
//============================================================================
typedef pair<AstVar*,AstNode*> V3TaskConnect; // [port, pin-connects-to]
typedef pair<AstVar*,AstArg*> V3TaskConnect; // [port, pin-connects-to]
typedef vector<V3TaskConnect> V3TaskConnects; // [ [port, pin-connects-to] ... ]
//============================================================================
+33 -12
View File
@@ -468,9 +468,9 @@ private:
if (m_doGenerate) {
UINFO(5, "Selection index out of range inside generate."<<endl);
} else {
nodep->v3error("Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<frommsb<<":"<<fromlsb);
nodep->v3warn(SELRANGE,"Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<frommsb<<":"<<fromlsb);
UINFO(1," Related node: "<<nodep<<endl);
}
}
@@ -852,7 +852,7 @@ private:
|| nodep->dtypeSkipRefp()->castNodeClassDType())) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
}
if (nodep->dtypeSkipRefp()->castConstDType()) {
if (nodep->dtypep()->skipRefToConstp()->castConstDType()) {
nodep->isConst(true);
}
// Parameters if implicit untyped inherit from what they are assigned to
@@ -915,6 +915,9 @@ private:
if (!nodep->valuep()->castInitArray()) { // No dtype at present, perhaps TODO
widthCheck(nodep,"Initial value",nodep->valuep(),nodep->width(),nodep->widthMin());
}
if (nodep->isDouble() && !nodep->valuep()->isDouble()) {
spliceCvtD(nodep->valuep());
}
}
UINFO(4,"varWidthed "<<nodep<<endl);
//if (debug()) nodep->dumpTree(cout," InitOut: ");
@@ -1073,11 +1076,21 @@ private:
nodep->dtypeFrom(nodep->lhsp());
}
virtual void visit(AstIfaceRefDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," IFACEREF "<<nodep<<endl);
nodep->iterateChildren(*this, vup);
nodep->dtypep(nodep);
nodep->widthForce(1, 1); // Not really relevant
UINFO(4,"dtWidthed "<<nodep<<endl);
}
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," NODECLASS "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree("-class-in--");
if (!nodep->packed()) nodep->v3error("Unsupported: Unpacked struct/union");
if (!nodep->packed()) {
nodep->v3warn(UNPACKED, "Unsupported: Unpacked struct/union");
}
nodep->iterateChildren(*this); // First size all members
nodep->repairMemberCache();
// Determine bit assignments and width
@@ -1675,7 +1688,8 @@ private:
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
if (pinp!=NULL) { // Else argument error we'll find later
if (accept_mode==0) {
// Prelim may cause the node to get replaced; we've lost our
@@ -1684,18 +1698,21 @@ private:
&& (!pinp->castSFormatF() || pinp->nextp())) { // Not already done
UINFO(4," sformat via metacomment: "<<nodep<<endl);
AstNRelinker handle;
pinp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
AstNode* argsp = NULL;
if (pinp->nextp()) argsp = pinp->nextp()->unlinkFrBackWithNext();
while (AstArg* nextargp = argp->nextp()->castArg()) {
argsp = argsp->addNext(nextargp->exprp()->unlinkFrBackWithNext()); // Expression goes to SFormatF
nextargp->unlinkFrBack()->deleteTree(); // Remove the call's Arg wrapper
}
string format;
if (pinp->castConst()) format = pinp->castConst()->num().toString();
else pinp->v3error("Format to $display-like function must have constant format string");
pushDeletep(pinp); pinp=NULL;
pushDeletep(argp); argp=NULL;
AstSFormatF* newp = new AstSFormatF(nodep->fileline(), format, false, argsp);
if (!newp->scopeNamep() && newp->formatScopeTracking()) {
newp->scopeNamep(new AstScopeName(newp->fileline()));
}
handle.relink(newp);
handle.relink(new AstArg(newp->fileline(), "", newp));
// Connection list is now incorrect (has extra args in it).
goto reloop; // so exit early; next loop will correct it
}
@@ -2236,12 +2253,16 @@ private:
void widthCheck (AstNode* nodep, const char* side,
AstNode* underp, AstNodeDType* expDTypep,
bool ignoreWarn=false) {
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e="<<expDTypep<<" i"<<ignoreWarn<<endl);
int expWidth = expDTypep->width();
int expWidthMin = expDTypep->widthMin();
if (expWidthMin==0) expWidthMin = expWidth;
bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if ((bad || underp->width() !=expWidth)
&& fixAutoExtend(underp/*ref*/,expWidth)) {
underp=NULL; // Changes underp
return;
}
if (underp->castConst() && underp->castConst()->num().isFromString()
&& expWidth > underp->width()
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
+5 -3
View File
@@ -307,13 +307,15 @@ private:
newp->dtypeFrom(adtypep);
} else {
// Need a slice data type, which is an array of the extracted type, but with (presumably) different size
VNumRange newRange (msb, lsb, fromRange.littleEndian());
AstNodeDType* vardtypep = new AstPackArrayDType(nodep->fileline(),
adtypep->subDTypep(), // Need to strip off array reference
new AstRange(nodep->fileline(), fromRange));
new AstRange(nodep->fileline(), newRange));
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
newp->dtypeFrom(vardtypep);
}
if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
//if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
if (newp->widthMin()!=(int)newp->widthConst()) nodep->v3fatalSrc("Width mismatch");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (ddtypep->castBasicDType()) {
@@ -387,7 +389,7 @@ private:
VNumRange fromRange = fromdata.m_fromRange;
if (ddtypep->castBasicDType()
|| (ddtypep->castNodeClassDType()
&& ddtypep->castNodeClassDType()->packed())) {
&& ddtypep->castNodeClassDType()->packedUnsup())) {
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (fromRange.littleEndian()) {
+79 -80
View File
@@ -141,8 +141,8 @@ void V3Global::readFiles() {
}
}
void V3Global::dumpGlobalTree(const string& filename, int newNumber) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(filename, newNumber));
void V3Global::dumpCheckGlobalTree(const string& filename, int newNumber, bool doDump) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(filename, newNumber), false, doDump);
}
//######################################################################
@@ -152,26 +152,26 @@ void process () {
// Sort modules by level so later algorithms don't need to care
V3LinkLevel::modSortByLevel();
V3Global::dumpGlobalTree("cells.tree");
V3Global::dumpCheckGlobalTree("cells.tree");
V3Error::abortIfErrors();
// Convert parseref's to varrefs, and other directly post parsing fixups
V3LinkParse::linkParse(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkparse.tree");
V3Global::dumpCheckGlobalTree("linkparse.tree", 0, dumpMore);
// Cross-link signal names
// Cross-link dotted hierarchical references
V3LinkDot::linkDotPrimary(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree", 0, dumpMore);
v3Global.checkTree(); // Force a check, as link is most likely place for problems
// Correct state we couldn't know at parse time, repair SEL's
V3LinkResolve::linkResolve(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkresolve.tree");
V3Global::dumpCheckGlobalTree("linkresolve.tree", 0, dumpMore);
// Set Lvalue's in variable refs
V3LinkLValue::linkLValue(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linklvalue.tree");
V3Global::dumpCheckGlobalTree("linklvalue.tree", 0, dumpMore);
// Convert return/continue/disable to jumps
V3LinkJump::linkJump(v3Global.rootp());
V3Global::dumpGlobalTree("link.tree");
V3Global::dumpCheckGlobalTree("link.tree");
V3Error::abortIfErrors();
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link");
@@ -179,19 +179,19 @@ void process () {
// Remove parameters by cloning modules to de-parameterized versions
// This requires some width calculations and constant propagation
V3Param::param(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("param.tree");
V3Global::dumpCheckGlobalTree("param.tree", 0, dumpMore);
V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules
V3Global::dumpGlobalTree("paramlink.tree");
V3Global::dumpCheckGlobalTree("paramlink.tree");
V3Error::abortIfErrors();
// Remove any modules that were parameterized and are no longer referenced.
V3Dead::deadifyModules(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("dead.tree");
V3Global::dumpCheckGlobalTree("dead.tree", 0, dumpMore);
v3Global.checkTree();
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
V3Width::width(v3Global.rootp());
V3Global::dumpGlobalTree("width.tree");
V3Global::dumpCheckGlobalTree("width.tree");
V3Error::abortIfErrors();
@@ -199,19 +199,19 @@ void process () {
V3Width::widthCommit(v3Global.rootp());
v3Global.assertDTypesResolved(true);
v3Global.assertWidthsMatch(true);
if (dumpMore) V3Global::dumpGlobalTree("widthcommit.tree");
V3Global::dumpCheckGlobalTree("widthcommit.tree", 0, dumpMore);
// Coverage insertion
// Before we do dead code elimination and inlining, or we'll lose it.
if (v3Global.opt.coverage()) {
V3Coverage::coverage(v3Global.rootp());
V3Global::dumpGlobalTree("coverage.tree");
V3Global::dumpCheckGlobalTree("coverage.tree");
}
// Push constants, but only true constants preserving liveness
// so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..."
V3Const::constifyAllLive(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Signal based lint checks, no change to structures
// Must be before first constification pass drops dead code
@@ -220,53 +220,52 @@ void process () {
// Assertion insertion
// After we've added block coverage, but before other nasty transforms
V3AssertPre::assertPreAll(v3Global.rootp());
V3Global::dumpGlobalTree("assertpre.tree");
V3Global::dumpCheckGlobalTree("assertpre.tree");
//
V3Assert::assertAll(v3Global.rootp());
V3Global::dumpGlobalTree("assert.tree");
V3Global::dumpCheckGlobalTree("assert.tree");
if (!v3Global.opt.xmlOnly()) {
// Add top level wrapper with instance pointing to old top
// Move packages to under new top
// Must do this after we know the width of any parameters
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
// Must do this after we know parameters and dtypes (as don't clone dtype decls)
V3LinkLevel::wrapTop(v3Global.rootp());
}
// Propagate constants into expressions
V3Const::constifyAllLint(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
if (!v3Global.opt.xmlOnly()) {
// Remove cell arrays (must be between V3Width and scoping)
V3Inst::dearrayAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("dearray.tree");
V3Global::dumpCheckGlobalTree("dearray.tree", 0, dumpMore);
}
if (!v3Global.opt.xmlOnly()) {
// Expand inouts, stage 2
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
V3Tristate::tristateAll(v3Global.rootp());
V3Global::dumpGlobalTree("tristate.tree");
V3Global::dumpCheckGlobalTree("tristate.tree");
// Task inlining & pushing BEGINs names to variables/cells
// Begin processing must be after Param, before module inlining
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
V3Global::dumpGlobalTree("begin.tree");
V3Global::dumpCheckGlobalTree("begin.tree");
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
V3Global::dumpGlobalTree("unknown.tree");
V3Global::dumpCheckGlobalTree("unknown.tree");
// Module inlining
// Cannot remove dead variables after this, as alias information for final
// V3Scope's V3LinkDot is in the AstVar.
if (v3Global.opt.oInline()) {
V3Inline::inlineAll(v3Global.rootp());
V3Global::dumpGlobalTree("inline.tree");
V3Global::dumpCheckGlobalTree("inline.tree");
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
if (dumpMore) V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree", 0, dumpMore);
}
}
@@ -274,11 +273,11 @@ void process () {
// Initial const/dead to reduce work for ordering code
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
v3Global.checkTree();
V3Dead::deadifyDTypes(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
v3Global.checkTree();
V3Error::abortIfErrors();
@@ -291,17 +290,17 @@ void process () {
// Convert instantiations to wassigns and always blocks
V3Inst::instAll(v3Global.rootp());
V3Global::dumpGlobalTree("inst.tree");
V3Global::dumpCheckGlobalTree("inst.tree");
// Inst may have made lots of concats; fix them
V3Const::constifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
V3Scope::scopeAll(v3Global.rootp());
V3Global::dumpGlobalTree("scope.tree");
V3Global::dumpCheckGlobalTree("scope.tree");
V3LinkDot::linkDotScope(v3Global.rootp());
V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree");
}
//--SCOPE BASED OPTIMIZATIONS--------------
@@ -309,87 +308,87 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Cleanup
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyDTypes(v3Global.rootp());
v3Global.checkTree();
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Convert case statements to if() blocks. Must be after V3Unknown
// Must be before V3Task so don't need to deal with task in case value compares
V3Case::caseAll(v3Global.rootp());
V3Global::dumpGlobalTree("case.tree");
V3Global::dumpCheckGlobalTree("case.tree");
// Inline all tasks
V3Task::taskAll(v3Global.rootp());
V3Global::dumpGlobalTree("task.tree");
V3Global::dumpCheckGlobalTree("task.tree");
// Add __PVT's
// After V3Task so task internal variables will get renamed
V3Name::nameAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("name.tree");
V3Global::dumpCheckGlobalTree("name.tree", 0, dumpMore);
// Loop unrolling & convert FORs to WHILEs
V3Unroll::unrollAll(v3Global.rootp());
V3Global::dumpGlobalTree("unroll.tree");
V3Global::dumpCheckGlobalTree("unroll.tree");
// Expand slices of arrays
V3Slice::sliceAll(v3Global.rootp());
V3Global::dumpGlobalTree("slices.tree");
V3Global::dumpCheckGlobalTree("slices.tree");
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
V3Global::dumpGlobalTree("life.tree");
V3Global::dumpCheckGlobalTree("life.tree");
}
// Make large low-fanin logic blocks into lookup tables
// This should probably be done much later, once we have common logic elimination.
if (!v3Global.opt.lintOnly() && v3Global.opt.oTable()) {
V3Table::tableAll(v3Global.rootp());
V3Global::dumpGlobalTree("table.tree");
V3Global::dumpCheckGlobalTree("table.tree");
}
// Cleanup
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyDTypes(v3Global.rootp());
v3Global.checkTree();
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Detect clock enables and mode into sensitives, and split always based on clocks
// (so this is a good prelude to splitAlways.)
if (v3Global.opt.oFlopGater()) {
V3ClkGater::clkGaterAll(v3Global.rootp());
V3Global::dumpGlobalTree("clkgater.tree");
V3Global::dumpCheckGlobalTree("clkgater.tree");
}
// Move assignments/sensitives into a SBLOCK for each unique sensitivity list
// (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
V3Active::activeAll(v3Global.rootp());
V3Global::dumpGlobalTree("active.tree");
V3Global::dumpCheckGlobalTree("active.tree");
// Split single ALWAYS blocks into multiple blocks for better ordering chances
if (v3Global.opt.oSplit()) {
V3Split::splitAlwaysAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("split.tree");
V3Global::dumpCheckGlobalTree("split.tree", 0, dumpMore);
}
V3SplitAs::splitAsAll(v3Global.rootp());
V3Global::dumpGlobalTree("splitas.tree");
V3Global::dumpCheckGlobalTree("splitas.tree");
// Create tracing sample points, before we start eliminating signals
if (v3Global.opt.trace()) {
V3TraceDecl::traceDeclAll(v3Global.rootp());
V3Global::dumpGlobalTree("tracedecl.tree");
V3Global::dumpCheckGlobalTree("tracedecl.tree");
}
// Gate-based logic elimination; eliminate signals and push constant across cell boundaries
// Instant propagation makes lots-o-constant reduction possibilities.
if (v3Global.opt.oGate()) {
V3Gate::gateAll(v3Global.rootp());
V3Global::dumpGlobalTree("gate.tree");
V3Global::dumpCheckGlobalTree("gate.tree");
// V3Gate calls constant propagation itself.
} else {
v3info("Command Line disabled gate optimization with -Og/-O0. This may cause ordering problems.");
@@ -398,14 +397,14 @@ void process () {
// Combine COVERINCs with duplicate terms
if (v3Global.opt.coverage()) {
V3CoverageJoin::coverageJoin(v3Global.rootp());
V3Global::dumpGlobalTree("coveragejoin.tree");
V3Global::dumpCheckGlobalTree("coveragejoin.tree");
}
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Clock domain crossing analysis
if (v3Global.opt.cdc()) {
@@ -417,34 +416,34 @@ void process () {
// Reorder assignments in pipelined blocks
if (v3Global.opt.oReorder()) {
V3Split::splitReorderAll(v3Global.rootp());
V3Global::dumpGlobalTree("reorder.tree");
V3Global::dumpCheckGlobalTree("reorder.tree");
}
// Create delayed assignments
// This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
V3Delayed::delayedAll(v3Global.rootp());
V3Global::dumpGlobalTree("delayed.tree");
V3Global::dumpCheckGlobalTree("delayed.tree");
// Make Active's on the top level
// Differs from V3Active, because identical clocks may be pushed down to a module and now be identical
V3ActiveTop::activeTopAll(v3Global.rootp());
V3Global::dumpGlobalTree("activetop.tree");
V3Global::dumpCheckGlobalTree("activetop.tree");
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
// Order the code; form SBLOCKs and BLOCKCALLs
V3Order::orderAll(v3Global.rootp());
V3Global::dumpGlobalTree("order.tree");
V3Global::dumpCheckGlobalTree("order.tree");
#ifndef NEW_ORDERING
// Change generated clocks to look at delayed signals
V3GenClk::genClkAll(v3Global.rootp());
V3Global::dumpGlobalTree("genclk.tree");
V3Global::dumpCheckGlobalTree("genclk.tree");
#endif
// Convert sense lists into IF statements.
V3Clock::clockAll(v3Global.rootp());
V3Global::dumpGlobalTree("clock.tree");
V3Global::dumpCheckGlobalTree("clock.tree");
// Cleanup any dly vars or other temps that are simple assignments
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
@@ -456,19 +455,19 @@ void process () {
V3LifePost::lifepostAll(v3Global.rootp());
}
if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
V3Global::dumpGlobalTree("life.tree");
V3Global::dumpCheckGlobalTree("life.tree");
}
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
#ifndef NEW_ORDERING
// Detect change loop
V3Changed::changedAll(v3Global.rootp());
V3Global::dumpGlobalTree("changed.tree");
V3Global::dumpCheckGlobalTree("changed.tree");
#endif
// Create tracing logic, since we ripped out some signals the user might want to trace
@@ -476,14 +475,14 @@ void process () {
// (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
if (v3Global.opt.trace()) {
V3Trace::traceAll(v3Global.rootp());
V3Global::dumpGlobalTree("trace.tree");
V3Global::dumpCheckGlobalTree("trace.tree");
}
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");
// Remove scopes; make varrefs/funccalls relative to current module
V3Descope::descopeAll(v3Global.rootp());
V3Global::dumpGlobalTree("descope.tree");
V3Global::dumpCheckGlobalTree("descope.tree");
}
//--MODULE OPTIMIZATIONS--------------
@@ -492,19 +491,19 @@ void process () {
// Split deep blocks to appease MSVC++. Must be before Localize.
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
V3DepthBlock::depthBlockAll(v3Global.rootp());
V3Global::dumpGlobalTree("deepblock.tree");
V3Global::dumpCheckGlobalTree("deepblock.tree");
}
// Move BLOCKTEMPS from class to local variables
if (v3Global.opt.oLocalize()) {
V3Localize::localizeAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("localize.tree");
V3Global::dumpCheckGlobalTree("localize.tree", 0, dumpMore);
}
// Icache packing; combine common code in each module's functions into subroutines
if (v3Global.opt.oCombine()) {
V3Combine::combineAll(v3Global.rootp());
V3Global::dumpGlobalTree("combine.tree");
V3Global::dumpCheckGlobalTree("combine.tree");
}
}
@@ -515,9 +514,9 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Here down, widthMin() is the Verilog width, and width() is the C++ width
// Bits between widthMin() and width() are irrelevant, but may be non zero.
@@ -525,18 +524,18 @@ void process () {
// Make all math operations either 8, 16, 32 or 64 bits
V3Clean::cleanAll(v3Global.rootp());
V3Global::dumpGlobalTree("clean.tree");
V3Global::dumpCheckGlobalTree("clean.tree");
// Move wide constants to BLOCK temps.
V3Premit::premitAll(v3Global.rootp());
V3Global::dumpGlobalTree("premit.tree");
V3Global::dumpCheckGlobalTree("premit.tree");
}
// Expand macros and wide operators into C++ primitives
if (!v3Global.opt.xmlOnly()
&& v3Global.opt.oExpand()) {
V3Expand::expandAll(v3Global.rootp());
V3Global::dumpGlobalTree("expand.tree");
V3Global::dumpCheckGlobalTree("expand.tree");
}
// Propagate constants across WORDSEL arrayed temporaries
@@ -544,18 +543,18 @@ void process () {
&& v3Global.opt.oSubst()) {
// Constant folding of expanded stuff
V3Const::constifyCpp(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
V3Subst::substituteAll(v3Global.rootp());
V3Global::dumpGlobalTree("subst.tree");
V3Global::dumpCheckGlobalTree("subst.tree");
}
if (!v3Global.opt.xmlOnly()
&& v3Global.opt.oSubstConst()) {
// Constant folding of substitutions
V3Const::constifyCpp(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("constc.tree");
V3Global::dumpCheckGlobalTree("constc.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("dead.tree");
V3Global::dumpCheckGlobalTree("dead.tree");
}
if (!v3Global.opt.lintOnly()
@@ -563,7 +562,7 @@ void process () {
// Fix very deep expressions
// Mark evaluation functions as member functions, if needed.
V3Depth::depthAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("depth.tree");
V3Global::dumpCheckGlobalTree("depth.tree", 0, dumpMore);
// Branch prediction
V3Branch::branchAll(v3Global.rootp());
@@ -571,7 +570,7 @@ void process () {
// Add C casts when longs need to become long-long and vice-versa
// Note depth may insert something needing a cast, so this must be last.
V3Cast::castAll(v3Global.rootp());
V3Global::dumpGlobalTree("cast.tree");
V3Global::dumpCheckGlobalTree("cast.tree");
}
V3Error::abortIfErrors();
@@ -677,7 +676,7 @@ int main(int argc, char** argv, char** env) {
}
// Final steps
V3Global::dumpGlobalTree("final.tree",99);
V3Global::dumpCheckGlobalTree("final.tree",990);
V3Error::abortIfWarnings();
if (!v3Global.opt.lintOnly() && !v3Global.opt.cdc()
+3 -3
View File
@@ -417,6 +417,7 @@ word [a-zA-Z0-9_]+
"do" { FL; return yDO; }
"endclocking" { FL; return yENDCLOCKING; }
"endpackage" { FL; return yENDPACKAGE; }
"endinterface" { FL; return yENDINTERFACE; }
"endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; }
"enum" { FL; return yENUM; }
@@ -425,9 +426,11 @@ word [a-zA-Z0-9_]+
"iff" { FL; return yIFF; }
"import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; }
"interface" { FL; return yINTERFACE; }
"int" { FL; return yINT; }
"logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; }
"modport" { FL; return yMODPORT; }
"package" { FL; return yPACKAGE; }
"packed" { FL; return yPACKED; }
"priority" { FL; return yPRIORITY; }
@@ -460,7 +463,6 @@ word [a-zA-Z0-9_]+
"dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -470,13 +472,11 @@ word [a-zA-Z0-9_]+
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
+146 -15
View File
@@ -85,6 +85,7 @@ public:
}
// METHODS
void argWrapList(AstNodeFTaskRef* nodep);
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
@@ -310,6 +311,7 @@ class AstSenTree;
%token<fl> yENDCLOCKING "endclocking"
%token<fl> yENDFUNCTION "endfunction"
%token<fl> yENDGENERATE "endgenerate"
%token<fl> yENDINTERFACE "endinterface"
%token<fl> yENDMODULE "endmodule"
%token<fl> yENDPACKAGE "endpackage"
%token<fl> yENDPRIMITIVE "endprimitive"
@@ -337,9 +339,11 @@ class AstSenTree;
%token<fl> yINSIDE "inside"
%token<fl> yINT "int"
%token<fl> yINTEGER "integer"
%token<fl> yINTERFACE "interface"
%token<fl> yLOCALPARAM "localparam"
%token<fl> yLOGIC "logic"
%token<fl> yLONGINT "longint"
%token<fl> yMODPORT "modport"
%token<fl> yMODULE "module"
%token<fl> yNAND "nand"
%token<fl> yNEGEDGE "negedge"
@@ -650,7 +654,7 @@ descriptionList: // IEEE: part of source_text
description: // ==IEEE: description
module_declaration { }
// // udp_declaration moved into module_declaration
//UNSUP interface_declaration { }
| interface_declaration { }
| program_declaration { }
| package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
@@ -844,14 +848,18 @@ port<nodep>: // ==IEEE: port
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
// // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation
//UNSUP portDirNetE id/*interface*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PARSEP->instantCb($<fl>2, $2, $3, $4); PINNUMINC(); }
//UNSUP portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PINNUMINC(); }
//UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PARSEP->instantCb($<fl>2, $2, $5, $6); PINNUMINC(); }
//UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PINNUMINC(); }
portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE
{ $$ = $3; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN);
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2));
$$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig rangeListE sigAttrListE
{ $$ = $5; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN);
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2,*$4));
$$->addNextNull(VARDONEP($$,$6,$7)); }
| portDirNetE yINTERFACE portSig rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); $$=NULL; }
| portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); $$=NULL; }
//
// // IEEE: ansi_port_declaration, with [port_direction] removed
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
@@ -889,7 +897,7 @@ port<nodep>: // ==IEEE: port
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE
//UNSUP { UNSUP }
//
portDirNetE data_type portSig variable_dimensionListE sigAttrListE
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
@@ -932,6 +940,54 @@ portSig<nodep>:
//**********************************************************************
// Interface headers
interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
// // timeunits_delcarationE is instead in interface_item
intFront parameter_port_listE portsStarE ';'
interface_itemListE yENDINTERFACE endLabelE
{ if ($2) $1->addStmtp($2);
if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1); }
//UNSUP yEXTERN intFront parameter_port_listE portsStarE ';' { }
;
intFront<modulep>:
yINTERFACE lifetimeE idAny/*new_interface*/
{ $$ = new AstIface($1,*$3);
$$->inLibrary(true);
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
interface_itemListE<nodep>:
/* empty */ { $$ = NULL; }
| interface_itemList { $$ = $1; }
;
interface_itemList<nodep>:
interface_item { $$ = $1; }
| interface_itemList interface_item { $$ = $1->addNextNull($2); }
;
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
port_declaration ';' { $$ = $1; }
// // IEEE: non_port_interface_item
//UNSUP generate_region { $$ = $1; }
| interface_or_generate_item { $$ = $1; }
//UNSUP program_declaration { $$ = $1; }
//UNSUP interface_declaration { $$ = $1; }
| timeunits_declaration { $$ = $1; }
// // See note in interface_or_generate item
| module_common_item { $$ = $1; }
;
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
// // module_common_item in interface_item, as otherwise duplicated
// // with module_or_generate_item's module_common_item
modport_declaration { $$ = $1; }
//UNSUP extern_tf_declaration { $$ = $1; }
;
//**********************************************************************
// Program headers
@@ -989,6 +1045,46 @@ program_generate_item<nodep>: // ==IEEE: program_generate_item
//UNSUP elaboration_system_task { $$ = $1; }
;
modport_declaration<nodep>: // ==IEEE: modport_declaration
yMODPORT modport_itemList ';' { $$ = $2; }
;
modport_itemList<nodep>: // IEEE: part of modport_declaration
modport_item { $$ = $1; }
| modport_itemList ',' modport_item { $$ = $1->addNextNull($3); }
;
modport_item<nodep>: // ==IEEE: modport_item
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
;
modportPortsDeclList<modportvarrefp>:
modportPortsDecl { $$ = $1; }
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
;
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
// We've expanded the lists each take to instead just have standalone ID ports.
// We track the type as with the V2k series of defines, then create as each ID is seen.
modportPortsDecl<modportvarrefp>:
// // IEEE: modport_simple_ports_declaration
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
// // IEEE: modport_clocking_declaration
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
//UNSUP yIMPORT modport_tf_port { }
//UNSUP yEXPORT modport_tf_port { }
// Continuations of above after a comma.
// // IEEE: modport_simple_ports_declaration
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
;
modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
id { $$ = $1; }
//UNSUP '.' idAny '(' ')' { }
//UNSUP '.' idAny '(' expr ')' { }
;
//************************************************
// Variable Declarations
@@ -2375,6 +2471,7 @@ funcRef<nodep>: // IEEE: part of tf_call
// // property_instance property_identifier property_actual_arg
// // sequence_instance sequence_identifier sequence_actual_arg
// // let_expression let_identifier let_actual_arg
//
id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2, *$1, $3); }
| package_scopeIdFollows id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($<fl>2, $1, new AstFuncRef($<fl>2,*$2,$4)); }
//UNSUP: idDotted is really just id to allow dotted method calls
@@ -2402,7 +2499,7 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
| yaD_IGNORE '(' exprList ')' { $$ = new AstSysIgnore($<fl>1,$3); }
//
| yaD_DPI parenE { $$ = new AstTaskRef($<fl>1,*$1,NULL); }
| yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($2,*$1,$3); }
| yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($2,*$1,$3); GRAMMARP->argWrapList($$->castTaskRef()); }
//
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
| yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); }
@@ -2447,7 +2544,7 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yaD_IGNORE '(' exprList ')' { $$ = new AstConst($2,V3Number($2,"'b0")); } // Unsized 0
//
| yaD_DPI parenE { $$ = new AstFuncRef($<fl>1,*$1,NULL); }
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); }
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); GRAMMARP->argWrapList($$->castFuncRef()); }
//
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
| yD_BITS '(' data_type ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
@@ -2503,9 +2600,10 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
;
list_of_argumentsE<nodep>: // IEEE: [list_of_arguments]
/* empty */ { $$ = NULL; }
| argsExprList { $$ = $1; }
//UNSUP empty arguments with just ,,
argsDottedList { $$ = $1; }
| argsExprListE { if ($1->castArg() && $1->castArg()->emptyConnectNoNext()) { $1->deleteTree(); $$ = NULL; } // Mis-created when have 'func()'
/*cont*/ else $$ = $1; }
| argsExprListE ',' argsDottedList { $$ = $1->addNextNull($3); }
;
task_declaration<ftaskp>: // ==IEEE: task_declaration
@@ -2968,6 +3066,26 @@ argsExprList<nodep>: // IEEE: part of list_of_arguments (used where ,, isn't le
| argsExprList ',' expr { $$ = $1->addNext($3); }
;
argsExprListE<nodep>: // IEEE: part of list_of_arguments
argsExprOneE { $$ = $1; }
| argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); }
;
argsExprOneE<nodep>: // IEEE: part of list_of_arguments
/*empty*/ { $$ = new AstArg(CRELINE(),"",NULL); }
| expr { $$ = new AstArg(CRELINE(),"",$1); }
;
argsDottedList<nodep>: // IEEE: part of list_of_arguments
argsDotted { $$ = $1; }
| argsDottedList ',' argsDotted { $$ = $1->addNextNull($3); }
;
argsDotted<nodep>: // IEEE: part of list_of_arguments
'.' idAny '(' ')' { $$ = new AstArg($1,*$2,NULL); }
| '.' idAny '(' expr ')' { $$ = new AstArg($1,*$2,$4); }
;
stream_expression<nodep>: // ==IEEE: stream_expression
// // IEEE: array_range_expression expanded below
expr { $$ = $1; }
@@ -3495,6 +3613,16 @@ void V3ParseImp::parserClear() {
VARDTYPE(NULL);
}
void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
// Convert list of expressions to list of arguments
AstNode* outp = NULL;
while (nodep->pinsp()) {
AstNode* exprp = nodep->pinsp()->unlinkFrBack();
outp = outp->addNext(new AstArg(exprp->fileline(), "", exprp));
}
if (outp) nodep->addPinsp(outp);
}
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int value) {
FileLine* newfl = new FileLine (fileline);
newfl->warnOff(V3ErrorCode::WIDTH, true);
@@ -3535,6 +3663,9 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
return NULL;
}
AstVarType type = GRAMMARP->m_varIO;
if (dtypep->castIfaceRefDType()) {
if (arrayp) { fileline->v3error("Unsupported: Arrayed interfaces"); arrayp=NULL; }
}
if (!dtypep) { // Created implicitly
dtypep = new AstBasicDType(fileline, LOGIC_IMPLICIT);
} else { // May make new variables with same type, so clone
+76 -29
View File
@@ -317,8 +317,10 @@ sub new {
pl_filename => undef, # Name of .pl file to get setup from
make_top_shell => 1, # Make a default __top.v file
make_main => 1, # Make __main.cpp
make_pli => 0, # need to compile pli
sim_time => 1100,
benchmark => $opt_benchmark,
verbose => $opt_verbose,
run_env => '',
# All compilers
v_flags => [split(/\s+/,(" -f input.vc "
@@ -331,7 +333,8 @@ sub new {
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
all_run_flags => [],
# ATSIM
pli_flags => ["-I$ENV{VERILATOR_ROOT}/include/vltstd -fPIC -export-dynamic -shared -o $self->{obj_dir}/libvpi.so"],
# ATSIM
atsim => 0,
atsim_flags => [split(/\s+/,"-c +sv +define+ATSIM"),
"+sv_dir+$self->{obj_dir}/.athdl_compile"],
@@ -348,6 +351,7 @@ sub new {
iv => 0,
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
iv_flags2 => [], # Overridden in some sim files
iv_pli => 0, # need to use pli
iv_run_flags => [],
# VCS
vcs => 0,
@@ -658,6 +662,16 @@ sub compile {
else {
$self->error("No compile step for this simulator");
}
if ($param{make_pli}) {
$self->oprint("Compile vpi\n");
my @cmd = ('g++', @{$param{pli_flags}}, "-DIS_VPI", "$self->{t_dir}/$self->{name}.cpp");
$self->_run(logfile=>"$self->{obj_dir}/pli_compile.log",
fails=>$param{fails},
cmd=>\@cmd);
}
return 1;
}
@@ -694,12 +708,16 @@ sub execute {
);
}
elsif ($param{iv}) {
my @cmd = ($run_env."$self->{obj_dir}/simiv",
@{$param{iv_run_flags}},
@{$param{all_run_flags}},
);
if ($param{iv_pli}) {
unshift @cmd, "vvp -n -m $self->{obj_dir}/libvpi.so"; # don't enter command line on $stop, include vpi
}
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
fails=>$param{fails},
cmd=>[$run_env."$self->{obj_dir}/simiv",
@{$param{iv_run_flags}},
@{$param{all_run_flags}},
],
cmd=> \@cmd,
%param,
expect=>$param{iv_run_expect}, # non-verilator expect isn't the same
);
@@ -861,30 +879,50 @@ sub _run {
print " > $param{logfile}" if $param{logfile};
print "\n";
if ($param{logfile}) {
open(SAVEOUT, ">&STDOUT") or die "%Error: Can't dup stdout";
open(SAVEERR, ">&STDERR") or die "%Error: Can't dup stderr";
if (0) {close(SAVEOUT); close(SAVEERR);} # Prevent unused warning
if ($param{tee}) {
open(STDOUT, "|tee $param{logfile}") or die "%Error: Can't redirect stdout";
} else {
open(STDOUT, ">$param{logfile}") or die "%Error: Can't open $param{logfile}";
# Execute command redirecting output, keeping order between stderr and stdout.
# Must do low-level IO so GCC interaction works (can't be line-based)
my $status;
{
pipe(PARENTRD, CHILDWR) or die "%Error: Can't Pipe, stopped";
autoflush PARENTRD 1;
autoflush CHILDWR 1;
my $logfh;
if ($param{logfile}) {
$logfh = IO::File->new(">$param{logfile}") or die "%Error: Can't open $param{logfile}";
}
open(STDERR, ">&STDOUT") or die "%Error: Can't dup stdout";
autoflush STDOUT 1;
autoflush STDERR 1;
my $pid=fork();
if ($pid) { # Parent
close CHILDWR;
while (1) {
my $buf = '';
my $got = sysread PARENTRD,$buf,10000;
last if defined $got && $got==0;
print $buf if $param{tee};
print $logfh $buf if $logfh;
}
close PARENTRD;
close $logfh if $logfh;
}
else { # Child
close PARENTRD;
close $logfh if $logfh;
# Reset signals
$SIG{ALRM} = 'DEFAULT';
$SIG{CHLD} = 'DEFAULT';
# Logging
open(STDOUT, ">&CHILDWR") or croak "%Error: Can't redirect stdout, stopped";
open(STDERR, ">&STDOUT") or croak "%Error: Can't dup stdout, stopped";
autoflush STDOUT 1;
autoflush STDERR 1;
system "$command";
exit ($? ? 10 : 0); # $?<<8 misses coredumps
}
waitpid($pid,0);
$status = $? || 0;
}
system "$command";
my $status = $?;
flush STDOUT;
flush STDERR;
if ($param{logfile}) {
open (STDOUT, ">&SAVEOUT");
open (STDERR, ">&SAVEERR");
}
if (!$param{fails} && $status) {
$self->error("Exec of $param{cmd}[0] failed\n");
}
@@ -1174,7 +1212,7 @@ sub _make_top_v {
print $fh " initial begin\n";
print $fh " \$display(\"-Tracing Waves to Dumpfile: $self->{vcd_filename}\");\n";
print $fh " \$dumpfile(\"$self->{vcd_filename}\");\n";
print $fh " \$dumpvars(12, t);\n";
print $fh " \$dumpvars(0, top);\n";
print $fh " end\n";
print $fh "`endif\n";
@@ -1277,14 +1315,23 @@ sub _read_inputs_v {
my $filename = $self->top_filename;
$filename = "$self->{t_dir}/$filename" if !-r $filename;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
my $get_sigs=1;
my %inputs;
while (defined(my $line = $fh->getline)) {
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
$self->{inputs}{$1} = $1;
if ($get_sigs) {
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
$inputs{$1} = $1;
}
if ($line =~ /^\s*(function|task|endmodule)/) {
$get_sigs = 0;
}
}
if ($line =~ /^\s*(function|task|endmodule)/) {
last;
if ($line =~ /^\s*module\s+t\b/) { # Ignore any earlier inputs; Module 't' has precedence
%inputs = ();
$get_sigs = 1;
}
}
$self->{inputs}{$_} = $inputs{$_} foreach keys %inputs;
$fh->close();
}
+78
View File
@@ -0,0 +1,78 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2013-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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "vpi_user.h"
class TestSimulator {
private:
struct SimTypes {
int verilator;
int icarus;
int mti;
int ncsim;
int vcs;
};
s_vpi_vlog_info m_info;
SimTypes m_simulators;
public:
TestSimulator() {
vpi_get_vlog_info(&m_info);
if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.verilator = true;
} else if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.icarus = true;
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
m_simulators.vcs = true;
} else {
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
__FILE__, __LINE__, m_info.product);
}
}
~TestSimulator() { }
// METHORS
private:
static TestSimulator& singleton() {
static TestSimulator s_singleton;
return s_singleton;
}
static const SimTypes& simulators() { return singleton().m_simulators; }
public:
static const s_vpi_vlog_info& get_info() { return singleton().m_info; }
// Simulator names
static bool is_icarus() { return simulators().icarus; }
static bool is_verilator() { return simulators().verilator; }
static bool is_mti() { return simulators().mti; }
static bool is_ncsim() { return simulators().ncsim; }
static bool is_vcs() { return simulators().vcs; }
// Simulator properties
static bool is_event_driven() { return !simulators().verilator; }
static bool has_get_scalar() { return !simulators().icarus; }
// return test level scope
static const char* top() {
if (simulators().verilator) {
return "t";
} else {
return "top.t";
}
}
// return absolute scope of obj
static const char* rooted(const char *obj) {
static char buf[256];
snprintf(buf, sizeof(buf), "%s.%s", top(), obj);
return buf;
}
};
#define VPI_HANDLE(signal) vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(signal), NULL);
+34
View File
@@ -0,0 +1,34 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2013-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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "vpi_user.h"
//======================================================================
class TestVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
bool m_free;
public:
TestVpiHandle() : m_handle(NULL), m_free(true) { }
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
operator vpiHandle () const { return m_handle; }
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
TestVpiHandle& nofree() {
m_free = false;
return *this;
}
};
+1 -4
View File
@@ -7,14 +7,11 @@ 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.
my $fail = ($Self->{v3} && verilator_version() !~ /\(ord\)/);
compile (
);
execute (
check_finished => !$fail,
fails => $fail,
check_finished => 1
);
ok(1);
@@ -7,10 +7,12 @@ 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} and $Self->unsupported("Verilator unsupported, bug102");
compile (
verilator_flags2 => ["--lint-only"]
verilator_flags2=>["-no-order-clock-delay"],
);
execute (
check_finished => 1
);
ok(1);
+131
View File
@@ -0,0 +1,131 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005 by Wilson Snyder.
module t (clk);
input clk;
reg [0:0] d1;
reg [2:0] d3;
reg [7:0] d8;
wire [0:0] q1;
wire [2:0] q3;
wire [7:0] q8;
// verilator lint_off UNOPTFLAT
reg ena;
// verilator lint_on UNOPTFLAT
condff #(12) condff
(.clk(clk), .sen(1'b0), .ena(ena),
.d({d8,d3,d1}),
.q({q8,q3,q1}));
integer cyc; initial cyc=1;
always @ (posedge clk) begin
if (cyc!=0) begin
//$write("%x %x %x %x\n", cyc, q8, q3, q1);
cyc <= cyc + 1;
if (cyc==1) begin
d1 <= 1'b1; d3<=3'h1; d8<=8'h11;
ena <= 1'b1;
end
if (cyc==2) begin
d1 <= 1'b0; d3<=3'h2; d8<=8'h33;
ena <= 1'b0;
end
if (cyc==3) begin
d1 <= 1'b1; d3<=3'h3; d8<=8'h44;
ena <= 1'b1;
// PROPER ANSWER is 8'h11, but we are negative-testing
//if (q8 != 8'h11) $stop;
if (q8 != 8'h33) $stop;
end
if (cyc==4) begin
d1 <= 1'b1; d3<=3'h4; d8<=8'h77;
ena <= 1'b1;
// PROPER ANSWER is 8'h11, but we are negative-testing
//if (q8 != 8'h11) $stop;
if (q8 != 8'h33) $stop;
end
if (cyc==5) begin
d1 <= 1'b1; d3<=3'h0; d8<=8'h88;
ena <= 1'b1;
// PROPER ANSWER is 8'h44, but we are negative-testing
//if (q8 != 8'h44) $stop;
end
if (cyc==6) begin
// PROPER ANSWER is 8'h77, but we are negative-testing
//if (q8 != 8'h77) $stop;
end
if (cyc==7) begin
// PROPER ANSWER is 8'h88, but we are negative-testing
//if (q8 != 8'h88) $stop;
end
//
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
end
endmodule
module condff (clk, sen, ena, d, q);
parameter WIDTH = 1;
input clk;
input sen;
input ena;
input [WIDTH-1:0] d;
output [WIDTH-1:0] q;
condffimp #(.WIDTH(WIDTH))
imp (.clk(clk), .sen(sen), .ena(ena), .d(d), .q(q));
endmodule
module condffimp (clk, sen, ena, d, q);
parameter WIDTH = 1;
input clk;
input sen;
input ena;
input [WIDTH-1:0] d;
output reg [WIDTH-1:0] q;
wire gatedclk;
clockgate clockgate (.clk(clk), .sen(sen), .ena(ena), .gatedclk(gatedclk));
always @(posedge gatedclk) begin
if (gatedclk === 1'bX) begin
q <= {WIDTH{1'bX}};
end
else begin
q <= d;
end
end
endmodule
module clockgate (clk, sen, ena, gatedclk);
input clk;
input sen;
input ena;
output gatedclk;
reg ena_b;
wire gatedclk = clk & ena_b;
// verilator lint_off COMBDLY
always @(clk or ena or sen) begin
if (~clk) begin
ena_b <= ena | sen;
end
else begin
if ((clk^sen)===1'bX) ena_b <= 1'bX;
end
end
// verilator lint_on COMBDLY
endmodule
+1 -4
View File
@@ -7,14 +7,11 @@ 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.
my $fail = ($Self->{v3} && verilator_version() !~ /\(ord\)/);
compile (
);
execute (
check_finished => !$fail,
fails => $fail,
check_finished => 1
);
ok(1);
+18 -1
View File
@@ -10,7 +10,21 @@ module t (/*AUTOARG*/
input clk;
reg toggle; initial toggle=0;
typedef struct packed {
union packed {
logic ua;
logic ub;
} u;
logic b;
} str_t;
reg toggle; initial toggle='0;
str_t stoggle; initial stoggle='0;
const reg aconst = '0;
reg [1:0][1:0] ptoggle; initial ptoggle=0;
integer cyc; initial cyc=1;
wire [7:0] cyc_copy = cyc[7:0];
@@ -51,6 +65,9 @@ module t (/*AUTOARG*/
cyc <= cyc + 1;
memory[cyc + 'd100] <= memory[cyc + 'd100] + 2'b1;
toggle <= '0;
stoggle.u <= toggle;
stoggle.b <= toggle;
ptoggle[0][0] <= toggle;
if (cyc==3) begin
toggle <= '1;
end
+5 -4
View File
@@ -38,10 +38,11 @@ if (!-r "$root/.git") {
# Check empty
my @files;
$finds = `find $destdir -type f -print`;
foreach my $f (split /\n/, $finds) {
print "\tLEFT: $f\n";
$f =~ s!^$cwd!.!;
push @files, $f;
foreach my $file (split /\n/, $finds) {
next if $file =~ /\.status/; # Made by driver.pl, not Verilator
print "\tLEFT: $file\n";
$file =~ s!^$cwd!.!;
push @files, $file;
}
if ($#files >= 0) {
$Self->error("Uninstall missed files: ",join(' ',@files));
+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 (
v_flags2 => ["t/t_dpi_string_c.cpp"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+26
View File
@@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2009 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
module t ();
import "DPI-C" function int dpii_string(input string DSM_NAME);
generate
begin : DSM
string SOME_STRING;
end
endgenerate
initial begin
$sformat(DSM.SOME_STRING, "%m");
if (dpii_string(DSM.SOME_STRING) != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+45
View File
@@ -0,0 +1,45 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License.
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include <cstdio>
#include <cstring>
#include "svdpi.h"
//======================================================================
#if defined(VERILATOR)
# include "Vt_dpi_string__Dpi.h"
#elif defined(VCS)
# include "../vc_hdrs.h"
#elif defined(CADENCE)
# define NEED_EXTERNS
#else
# error "Unknown simulator for DPI test"
#endif
#ifdef NEED_EXTERNS
extern "C" {
extern int dpii_string (const char* s);
}
#endif
//======================================================================
int dpii_string(const char* s) {
printf("dpii_string: %s\n",s);
return strlen(s);
}
+11
View File
@@ -34,6 +34,9 @@ module t (/*AUTOARG*/);
var logic [ONES:0] sized_based_on_enum;
var enum logic [3:0] { QINVALID='1, QSEND={2'b0,2'h0}, QOP={2'b0,2'h1}, QCL={2'b0,2'h2},
QPR={2'b0,2'h3 }, QACK, QRSP } inv;
initial begin
if (e0 !== 0) $stop;
if (e1 !== 1) $stop;
@@ -61,6 +64,14 @@ module t (/*AUTOARG*/);
if (FIVE[BIT1] != 1'b0) $stop;
if (FIVE[BIT2] != 1'b1) $stop;
if (QINVALID != 15) $stop;
if (QSEND != 0) $stop;
if (QOP != 1) $stop;
if (QCL != 2) $stop;
if (QPR != 3) $stop;
if (QACK != 4) $stop;
if (QRSP != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+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;
+27
View File
@@ -0,0 +1,27 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Charlie Brej.
module submodule ();
// This bug only appears when not inlining
// verilator no_inline_module
initial begin
$write("d");
end
final begin
$write("d");
end
endmodule
module t ();
generate
for (genvar i = 0; i < 100; i = i + 1) begin : module_set
submodule u_submodule ();
end
endgenerate
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+55
View File
@@ -0,0 +1,55 @@
#!/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.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
v_flags2 => ["--trace --output-split 1 --output-split-cfuncs 1"],
);
execute (
check_finished=>1,
);
my $got1;
foreach my $file (glob("$Self->{obj_dir}/*.cpp")) {
$got1 = 1 if $file =~ /__1/;
check($file);
}
$got1 or $Self->error("No __1 split file found");
ok(1);
1;
sub check {
my $filename = shift;
my $size = -s $filename;
printf " File %6d %s\n", $size, $filename if $Self->{verbose};
my $fh = IO::File->new("<$filename") or $Self->error("$! $filenme");
my @funcs;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^(void|IData)\s+(.*::.*)/) {
my $func = $2;
$func =~ s/\(.*$//;
print "\tFunc $func\n" if $Self->{verbose};
if ($func !~ /::_eval_initial_loop$/
&& $func !~ /::__Vconfigure$/
&& $func !~ /::trace$/
&& $func !~ /::traceInit$/
&& $func !~ /::traceFull$/
) {
push @funcs, $func;
}
}
}
if ($#funcs > 0) {
$Self->error("Split had multiple functions in $filename\n\t".join("\n\t",@funcs));
}
}
+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, 2005 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
parameter CNT = 10;
wire [31:0] w [CNT:0];
generate
for (genvar g=0; g<CNT; g++)
sub sub (.clk(clk), .i(w[g]), .z(w[g+1]));
endgenerate
// Test loop
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==0) begin
// Setup
w[0] = 32'h1234;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
`define EXPECTED_SUM 32'h123e
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d sum=%x\n",$time, cyc, w[CNT]);
`endif
if (w[CNT] !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub (input clk, input [31:0] i, output [31:0] z);
always @(posedge clk)
z <= i+1+$c("0"); // $c so doesn't optimize away
endmodule
+6 -2
View File
@@ -11,9 +11,13 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
q{%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
q{%Error: t/t_func_bad.v:\d+: Missing argument on non-defaulted argument 'from2' in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too many arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'
%Error: t/t_func_bad.v:\d+: Missing argument on non-defaulted argument 'y' in function call to TASK 'x'
%Error: t/t_func_bad.v:\d+: Unsupported: Function output argument 'y' requires 1 bits, but connection's CONST '.*' generates 32 bits.
%Error: t/t_func_bad.v:\d+: No such argument 'no_such' in function call to FUNC 'f'
%Error: t/t_func_bad.v:\d+: Duplicate argument 'dup' in function call to FUNC 'f'
%Error: t/t_func_bad.v:\d+: Too many arguments in function call to FUNC 'f'
%Error: Exiting due to},
);
+8
View File
@@ -9,6 +9,10 @@ module t;
if (add(3'd1, 3'd2, 3'd3) != 0) $stop; // Too many args
x; // Too few args
if (hasout(3'd1) != 0) $stop; // outputs
//
f(.j(1), .no_such(2)); // Name mismatch
f(.dup(1), .dup(3)); // Duplicate
f(1,2,3); // Too many
end
function [2:0] add;
@@ -29,4 +33,8 @@ module t;
hasout = 0;
endfunction
function int f( int j = 1, int dup = 0 );
return (j<<16) | dup;
endfunction
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+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, 2013 by Wilson Snyder.
module t (/*AUTOARG*/);
function int f( int j = 1, int s = 0 );
return (j<<16) | s;
endfunction
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
initial begin
`checkh( f(.j(2), .s(1)) , 32'h2_0001 );
`checkh( f(.s(1)) , 32'h1_0001 );
`checkh( f(, 1) , 32'h1_0001 );
`checkh( f(.j(2)) , 32'h2_0000 );
`checkh( f(.s(1), .j(2)) , 32'h2_0001 );
`checkh( f(.s(), .j()) , 32'h1_0000 );
`checkh( f(2) , 32'h2_0000 );
`checkh( f() , 32'h1_0000 );
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+55
View File
@@ -0,0 +1,55 @@
// DESCRIPTION: Verilator: Test of gated clock detection
//
// The code as shown generates a result by a delayed assignment from PC. The
// creation of the result is from a clock gated from the clock that sets
// PC. Howevever since they are essentially the same clock, the result should
// be delayed by one cycle.
//
// Standard Verilator treats them as different clocks, so the result stays in
// step with the PC. An event drive simulator always allows the clock to win.
//
// The problem is caused by the extra loop added by Verilator to the
// evaluation of all internally generated clocks (effectively removed by
// marking the clock enable).
//
// This test is added to facilitate experiments with solutions.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Jeremy Bennett <[email protected]>.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg gated_clk_en = 1'b0 ;
reg [1:0] pc = 2'b0;
reg [1:0] res = 2'b0;
wire gated_clk = gated_clk_en & clk;
always @(posedge clk) begin
pc <= pc + 1;
gated_clk_en <= 1'b1;
end
always @(posedge gated_clk) begin
res <= pc;
end
always @(posedge clk) begin
if (pc == 2'b11) begin
// Correct behaviour is that res should be lagging pc in the count
// by one cycle
if (res == 2'b10) begin
$write("*-* All Finished *-*\n");
$finish;
end
else begin
$stop;
end
end
end
endmodule
+5 -4
View File
@@ -11,10 +11,11 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
q{%Error: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Error: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Error: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Error: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
q{%Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Warning-SELRANGE: Use .*
%Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Warning-SELRANGE: t/t_gen_cond_bitrange_bad.v:\d+: Selection index out of range: 2:2 outside 1:0
%Error: Exiting due to .*},
);
-2
View File
@@ -7,8 +7,6 @@ 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} and $Self->unsupported("Verilator unsupported, bug102");
compile (
);
+3 -3
View File
@@ -100,7 +100,7 @@ interface handshake #(
// local logic (counter)
always @ (posedge clk, posedge rst)
if (rst) cnt <= '0;
else cnt <= cnt + inc;
else cnt <= cnt + {31'h0, inc};
endinterface : handshake
@@ -129,7 +129,7 @@ module source #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt);
else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// request signal
assign inf.req = rnd[0];
@@ -161,7 +161,7 @@ module drain #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt);
else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// grant signal
assign inf.grt = rnd[0];
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+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.
// Very simple test for interface pathclearing
interface ifc;
logic [3:0] value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4'h4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (c1.i_value != 4) $stop; // 'Normal' crossref just for comparison
if (itop.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc isub,
input logic [3:0] i_value
);
always @* begin
isub.value = i_value;
end
endmodule : sub
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+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.
// Very simple test for interface pathclearing
interface ifc;
integer hidden_from_isub;
integer value;
modport out_modport (output value);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop.value != 4) $stop;
itop.hidden_from_isub = 20;
if (itop.hidden_from_isub != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc.out_modport isub,
input integer i_value
);
always @* begin
isub.value = i_value;
end
endmodule
+1 -3
View File
@@ -7,10 +7,8 @@ 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} and $Self->unsupported("Verilator unsupported, bug102");
compile (
v_flags => []
verilator_flags2 => ["--top-module t"],
);
execute (
+53 -26
View File
@@ -3,11 +3,6 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
interface counter_io;
logic [3:0] value;
logic reset;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
@@ -18,17 +13,24 @@ module t (/*AUTOARG*/
counter_io c1_data();
counter_io c2_data();
//counter_io c3_data; // IEEE illegal, and VCS doesn't allow non-() as it does with cells
counter_io c3_data();
counter c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter2 c2 (.clkm(clk),
.c_data(c2_data),
.i_value(4'h2));
counter_ansi c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter_ansi c2 (.clkm(clk),
.c_data(c2_data),
.i_value(4'h2));
`ifdef VERILATOR counter_ansi `else counter_nansi `endif
/**/ c3 (.clkm(clk),
.c_data(c3_data),
.i_value(4'h3));
initial begin
c1_data.value = 4'h4;
c2_data.value = 4'h5;
c3_data.value = 4'h6;
end
always @ (posedge clk) begin
@@ -36,46 +38,71 @@ module t (/*AUTOARG*/
if (cyc<2) begin
c1_data.reset <= 1;
c2_data.reset <= 1;
c3_data.reset <= 1;
end
if (cyc==2) begin
c1_data.reset <= 0;
c2_data.reset <= 0;
c3_data.reset <= 0;
end
if (cyc==3) begin
if (c1_data.get_lcl() != 12345) $stop;
end
if (cyc==20) begin
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
$write("[%0t] c1 cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x\n", $time, cyc,
c1_data.value, c1_data.reset,
c2_data.value, c2_data.reset,
c3_data.value, c3_data.reset);
if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop;
if (c3_data.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module counter
interface counter_io;
logic [3:0] value;
logic reset;
integer lcl;
task set_lcl (input integer a); lcl=a; endtask
function integer get_lcl (); return lcl; endfunction
endinterface
interface ifunused;
logic unused;
endinterface
module counter_ansi
(
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;
initial begin
c_data.set_lcl(12345);
end
endmodule : counter
module counter2(clkm, c_data, i_value);
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_ansi
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi(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;
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter2
endmodule : counter_nansi
`endif
module modunused (ifunused ifinunused);
ifunused ifunused();
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+72
View File
@@ -0,0 +1,72 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
interface ifc;
integer value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
`ifdef INLINE_A //verilator inline_module
`else //verilator no_inline_module
`endif
input clk;
integer cyc=1;
ifc itop1a();
ifc itop1b();
ifc itop2a();
ifc itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14),
.i_valueb(15));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24),
.i_valueb(25));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.value != 14) $stop;
if (itop1b.value != 15) $stop;
if (itop2a.value != 24) $stop;
if (itop2b.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input integer i_valuea,
input integer i_valueb
);
`ifdef INLINE_B //verilator inline_module
`else //verilator no_inline_module
`endif
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input integer i_value
);
`ifdef INLINE_C //verilator inline_module
`else //verilator no_inline_module
`endif
always @* begin
isub.value = i_value;
end
endmodule
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, interface generates changing types");
$Self->{vcs} and $Self->unsupported("Commercially unsupported, interface crossrefs");
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+78
View File
@@ -0,0 +1,78 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// This test demonstrates how not only parameters but the type of a parent
// interface could propagate down to child modules, changing their data type
// determinations. Note presently unsupported in all commercial simulators.
interface ifc;
parameter MODE = 0;
generate
// Note block must be named per SystemVerilog 2005
if (MODE==1) begin : g
integer value;
end
else if (MODE==2) begin : g
real value;
end
endgenerate
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(1) itop1a();
ifc #(1) itop1b();
ifc #(2) itop2a();
ifc #(2) itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14.1),
.i_valueb(15.2));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24.3),
.i_valueb(25.4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.g.value != 14) $stop;
if (itop1b.g.value != 15) $stop;
if (itop2a.g.value != 24) $stop;
if (itop2b.g.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input real i_valuea,
input real i_valueb
);
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input real i_value
);
always @* begin
`error Commercial sims choke on cross ref here
isub.g.value = i_value;
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_interface_down.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_interface_down.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_interface_down.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_interface_down.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_interface_down.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_interface_down.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_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

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