Compare commits

...
44 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
88 changed files with 2748 additions and 387 deletions
+58
View File
@@ -3,6 +3,64 @@ 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]
+27 -1
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.
@@ -3212,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.850 2013-06-02])
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
+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));
+7 -1
View File
@@ -1153,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
@@ -1540,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; }
@@ -1589,12 +1592,14 @@ public:
// 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 {
@@ -1643,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;
+34 -3
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; }
@@ -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
@@ -427,7 +429,8 @@ 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(); }
};
@@ -456,6 +459,7 @@ public:
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; }
@@ -506,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; }
@@ -573,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
@@ -662,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(); }
};
@@ -961,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
@@ -1294,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)
@@ -3359,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(); }
};
@@ -3372,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(); }
};
+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*) {
+8 -2
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();
@@ -1643,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) {
+45 -1
View File
@@ -213,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),
@@ -224,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());
}
+13 -2
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
@@ -1418,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) {
@@ -1444,6 +1447,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
puts( " \"page\",pagep,");
puts( " \"comment\",commentp);\n");
puts("}\n");
splitSizeInc(10);
}
}
@@ -1453,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) {
@@ -1631,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");
@@ -1651,6 +1657,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts( "}\n");
#endif
puts("}\n");
splitSizeInc(10);
}
//----------------------------------------------------------------------
@@ -2111,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");
@@ -2123,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");
@@ -2131,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");
}
@@ -2147,6 +2157,7 @@ class EmitCTrace : EmitCStmts {
puts("t->traceChgThis (vlSymsp, vcdp, code);\n");
puts("}\n");
puts("}\n");
splitSizeInc(10);
puts("\n//======================\n\n");
}
+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())
+2 -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"
};
+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
+1 -1
View File
@@ -74,7 +74,7 @@ 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) {
+3
View File
@@ -68,8 +68,10 @@ void V3LinkLevel::modSortByLevel() {
vec.push_back(nodep);
}
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
}
//######################################################################
+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");
+9 -2
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;
+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; }
+26 -4
View File
@@ -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()) {
+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; }
};
+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;
+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));
+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] ... ]
//============================================================================
+25 -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: ");
@@ -1085,7 +1088,9 @@ private:
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
@@ -1683,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
@@ -1692,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
}
@@ -2244,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
+1 -1
View File
@@ -389,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()) {
+78 -78
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,10 +220,10 @@ 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
@@ -234,38 +234,38 @@ void process () {
// 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);
}
}
@@ -273,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();
@@ -290,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--------------
@@ -308,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.");
@@ -397,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()) {
@@ -416,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.
@@ -455,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
@@ -475,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--------------
@@ -491,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");
}
}
@@ -514,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.
@@ -524,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
@@ -543,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()
@@ -562,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());
@@ -570,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();
@@ -676,7 +676,7 @@ int main(int argc, char** argv, char** env) {
}
// Final steps
V3Global::dumpGlobalTree("final.tree",990);
V3Global::dumpCheckGlobalTree("final.tree",990);
V3Error::abortIfWarnings();
if (!v3Global.opt.lintOnly() && !v3Global.opt.cdc()
+54 -24
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);
@@ -847,24 +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
portDirNetE id/*interface*/ idAny/*port*/ variable_dimensionListE sigAttrListE
{ $$ = new AstPort($<fl>2,PINNUMINC(),*$3);
AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$3,VFlagChildDType(),
new AstIfaceRefDType($<fl>2,"",*$2));
if ($4) varp->v3error("Unsupported: Arrayed interfaces");
varp->addAttrsp($5);
$$->addNext(varp); }
| portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $$ = new AstPort($3,PINNUMINC(),*$5);
AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$5,VFlagChildDType(),
new AstIfaceRefDType($<fl>2,"",*$2,*$4));
if ($6) varp->v3error("Unsupported: Arrayed interfaces");
varp->addAttrsp($7);
$$->addNext(varp); }
| portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
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 ]
@@ -902,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)); }
@@ -2476,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
@@ -2503,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); }
@@ -2548,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); }
@@ -2604,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
@@ -3069,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; }
@@ -3596,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);
@@ -3636,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
+24 -6
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
);
@@ -1194,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";
+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);
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2=>["-no-order-clock-delay"],
);
execute (
check_finished => 1
);
ok(1);
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
+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 .*},
);
+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;
+47
View File
@@ -0,0 +1,47 @@
// 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;
modport i (output value);
modport o (input value);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop1a(),
itop1b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14),
.i_valueb(15));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.value != 14) $stop;
if (itop1b.value != 15) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc.i isuba, isubb,
input integer i_valuea, i_valueb
);
always @* begin
isuba.value = i_valuea;
isubb.value = i_valueb;
end
endmodule
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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} and $Self->unsupported("Verilator unsupported, bug659");
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+110
View File
@@ -0,0 +1,110 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Sean Moore.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [7:0] tripline = crc[7:0];
/*AUTOWIRE*/
wire valid;
wire [3-1:0] value;
PriorityChoice #(.OCODEWIDTH(3))
pe (.out(valid), .outN(value[2:0]), .tripline(tripline));
// Aggregate outputs into a single result vector
wire [63:0] result = {59'h0, valid, value};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'hc5fc632f816568fb
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module PriorityChoice (out, outN, tripline);
parameter OCODEWIDTH = 1;
localparam CODEWIDTH=OCODEWIDTH-1;
localparam SCODEWIDTH= (CODEWIDTH<1) ? 1 : CODEWIDTH;
output reg out;
output reg [OCODEWIDTH-1:0] outN;
input wire [(1<<OCODEWIDTH)-1:0] tripline;
wire left;
wire [SCODEWIDTH-1:0] leftN;
wire right;
wire [SCODEWIDTH-1:0] rightN;
generate
if(OCODEWIDTH==1) begin
assign left = tripline[1];
assign right = tripline[0];
always @(*) begin
out <= left || right ;
if(right) begin outN <= {1'b0}; end
else begin outN <= {1'b1}; end
end
end else begin
PriorityChoice #(.OCODEWIDTH(OCODEWIDTH-1))
leftMap
(
.out(left),
.outN(leftN),
.tripline(tripline[(2<<CODEWIDTH)-1:(1<<CODEWIDTH)])
);
PriorityChoice #(.OCODEWIDTH(OCODEWIDTH-1))
rightMap
(
.out(right),
.outN(rightN),
.tripline(tripline[(1<<CODEWIDTH)-1:0])
);
always @(*) begin
if(right) begin
out <= right;
outN <= {1'b0, rightN[OCODEWIDTH-2:0]};
end else begin
out <= left;
outN <= {1'b1, leftN[OCODEWIDTH-2:0]};
end
end
end
endgenerate
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;
+36
View File
@@ -0,0 +1,36 @@
// 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 integer max2;
input integer x;
input integer y;
begin
begin : blk
automatic int temp;
temp = x;
end
end
max2 = ( x > y ) ? x : y;
endfunction
function integer max4;
input integer x;
input integer y;
input integer z;
input integer w;
// MAX2 is used multiple times
max4 = max2( max2( x, y ), max2( z, w ) );
endfunction
localparam MAX4 = max4( 1, 1, 0, 0 );
initial begin
if (MAX4 != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+3 -2
View File
@@ -11,8 +11,9 @@ compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Error: t/t_select_bad_range.v:\d+: Selection index out of range: 44:44 outside 43:0
%Error: t/t_select_bad_range.v:\d+: Selection index out of range: 44:41 outside 43:0
'%Warning-SELRANGE: t/t_select_bad_range.v:\d+: Selection index out of range: 44:44 outside 43:0
%Warning-SELRANGE: Use .*
%Warning-SELRANGE: t/t_select_bad_range.v:\d+: Selection index out of range: 44:41 outside 43:0
%Error: Exiting due to.*',
);
+2 -1
View File
@@ -11,7 +11,8 @@ compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Error: t/t_select_bad_range2.v:\d+: Selection index out of range: 3:2 outside 1:0
'%Warning-SELRANGE: t/t_select_bad_range2.v:\d+: Selection index out of range: 3:2 outside 1:0
%Warning-SELRANGE: Use .*
%Error: Exiting due to.*',
);
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--lint-only"],
make_top_shell => 0,
make_main => 0,
verilator_make_gcc => 0,
);
ok(1);
1;
+36
View File
@@ -0,0 +1,36 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [7:0] x;
wire [3:0] en;
wire sel;
wire a;
// bug675
generate
genvar g_k;
for ( g_k = 0; g_k < 8; g_k = g_k + 1 )
begin: g_index
always @* begin
// Note this isn't a genif, but normal if
// verilator lint_off SELRANGE
if(g_k<4) begin
x[g_k] = (sel == 1'b1) ? 1'b1 : (en[g_k] == 1'b0) ? 1'b1 : a;
end
else begin
x[g_k] = (sel == 1'b0) ? 1'b1 : (en[g_k-4] == 1'b0) ? 1'b1 : a;
end
// verilator lint_on SELRANGE
end
end
endgenerate
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;
+26
View File
@@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module x;
// verilator lint_off UNPACKED
typedef struct {
int a;
} notpacked_t;
// verilator lint_on UNPACKED
typedef struct packed {
notpacked_t b;
} ispacked_t;
ispacked_t p;
initial begin
p.b = 1;
if (p.b != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+2 -1
View File
@@ -10,7 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
fails=>$Self->{v3},
expect=>
q{%Error: t/t_struct_unpacked_bad.v:8: Unsupported: Unpacked struct/union
q{%Warning-UNPACKED: t/t_struct_unpacked_bad.v:\d+: Unsupported: Unpacked struct/union
%Warning-UNPACKED: Use .*
.*%Error: Exiting due to.*},
);
+9 -1
View File
@@ -10,7 +10,15 @@ module x;
} notpacked_t;
typedef struct packed {
notpacked_t a;
notpacked_t b;
} ispacked_t;
ispacked_t p;
initial begin
p.b = 1;
if (p.b != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+20
View File
@@ -15,6 +15,10 @@ module t;
reg [16*8:1] letterz;
real r;
reg [7:0] v_a,v_b,v_c,v_d;
reg [31:0] v_worda;
reg [31:0] v_wordb;
`ifdef TEST_VERBOSE
`define verbose 1'b1
`else
@@ -174,6 +178,22 @@ module t;
if (chars != 1) $stop;
if (letterl != "\n") $stop;
// msg1229
v_a = $fgetc(file);
v_b = $fgetc(file);
v_c = $fgetc(file);
v_d = $fgetc(file);
v_worda = { v_d, v_c, v_b, v_a };
if (v_worda != "4321") $stop;
v_wordb[7:0] = $fgetc(file);
v_wordb[15:8] = $fgetc(file);
v_wordb[23:16] = $fgetc(file);
v_wordb[31:24] = $fgetc(file);
if (v_wordb != "9876") $stop;
if ($fgetc(file) != "\n") $stop;
$fclose(file);
end
@@ -6,3 +6,4 @@ widestuff
*oa=23 ob=12563
*d=-236123
*fredfishblah
12346789
+1 -1
View File
@@ -63,7 +63,7 @@ int main(int argc, char **argv, char **env) {
#elif defined(T_TRACE_CAT_RENEW)
tfp->close();
delete tfp;
VerilatedVcdC* tfp = new VerilatedVcdC;
tfp = new VerilatedVcdC;
top->trace(tfp,99);
tfp->open(trace_name());
#else
+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, 2011 by Wilson Snyder.
`begin_keywords "VAMS-2.3"
module t (/*autoarg*/
// Outputs
aout,
// Inputs
in
);
input [15:0] in;
output aout;
wreal aout;
parameter real lsb = 1;
// verilator lint_off WIDTH
assign aout = $itor(in) * lsb;
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+5
View File
@@ -12,8 +12,13 @@ module t (/*AUTOARG*/
const logic [2:0] five = 3'd5;
const logic unsigned [31:0] var_const = 22;
logic [7:0] res_const;
assign res_const = var_const[7:0]; // bug693
always @ (posedge clk) begin
if (five !== 3'd5) $stop;
if (res_const !== 8'd22) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+283
View File
@@ -0,0 +1,283 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2010-2011 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.
//
//*************************************************************************
#ifdef IS_VPI
#include "vpi_user.h"
#include <cstdlib>
#else
#include "Vt_vpi_get.h"
#include "verilated.h"
#include "svdpi.h"
#include "Vt_vpi_get__Dpi.h"
#include "verilated_vpi.h"
#include "verilated_vpi.cpp"
#include "verilated_vcd_c.h"
#endif
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_get.cpp"
#define TEST_MSG if (0) printf
unsigned int main_time = false;
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
FILENM,__LINE__, (got), (exp)); \
return __LINE__; \
}
#define CHECK_RESULT_NZ(got) \
if (!(got)) { \
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM,__LINE__); \
return __LINE__; \
}
// Use cout to avoid issues with %d/%lx etc
#define CHECK_RESULT(got, exp) \
if ((got) != (exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__ \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_HEX(got, exp) \
if ((got) != (exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__<<hex \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_CSTR(got, exp) \
if (strcmp((got),(exp))) { \
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", \
FILENM,__LINE__, (got)?(got):"<null>", (exp)?(exp):"<null>"); \
return __LINE__; \
}
#define CHECK_RESULT_CSTR_STRIP(got, exp) \
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int scalar, int type) {
s_vpi_value value = {
vpiIntVal
};
// check size of object
int vpisize = vpi_get(vpiSize, handle);
CHECK_RESULT(vpisize, size);
// icarus verilog does not support vpiScalar, vpiVector or vpi*Range
if (TestSimulator::has_get_scalar()) {
int vpiscalar = vpi_get(vpiScalar, handle);
CHECK_RESULT((bool)vpiscalar, (bool)scalar);
int vpivector = vpi_get(vpiVector, handle);
CHECK_RESULT((bool)vpivector, (bool)!scalar);
}
// Icarus only supports ranges on memories
if (!scalar && !(TestSimulator::is_icarus() && type != vpiMemory)) {
TestVpiHandle left_h, right_h;
// check coherency for vectors
// get left hand side of range
left_h = vpi_handle(vpiLeftRange, handle);
CHECK_RESULT_NZ(left_h);
vpi_get_value(left_h, &value);
int coherency = value.value.integer;
// get right hand side of range
right_h = vpi_handle(vpiRightRange, handle);
CHECK_RESULT_NZ(right_h);
vpi_get_value(right_h, &value);
TEST_MSG("%d:%d\n", coherency, value.value.integer);
coherency -= value.value.integer;
// calculate size & check
coherency = abs(coherency) + 1;
CHECK_RESULT(coherency, size);
}
// Only check direction on ports
if (type == vpiPort) {
// check direction of object
int vpidir = vpi_get(vpiDirection, handle);
// Don't check port directions in verilator
// see #681
if (!TestSimulator::is_verilator()) {
CHECK_RESULT(vpidir, direction);
}
}
// check type of object
int vpitype = vpi_get(vpiType, handle);
if (!(TestSimulator::is_verilator() && type == vpiPort)) {
// Don't check for ports in verilator
// see #681
CHECK_RESULT(vpitype, type);
}
return 0; // Ok
}
struct params {
const char* signal;
struct {
unsigned int size;
unsigned int direction;
unsigned int scalar;
unsigned int type;
} attributes, children;
} values[] = {
{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}},
{"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
{"onetwo", {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory}, {0, 0, 0, 0}},
{"fourthreetwoone", {2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiMemoryWord}},
{"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
{"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}},
{"testout", {24, vpiOutput, 0, vpiPort}, {0, 0, 0, 0}},
{"sub.subin", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
{"sub.subout", {1, vpiOutput, 1, vpiPort}, {0, 0, 0, 0}},
{NULL, {0, 0, 0, 0}, {0, 0, 0, 0}}
};
int mon_check_props() {
struct params* value = values;
while (value->signal) {
TestVpiHandle h = VPI_HANDLE(value->signal);
CHECK_RESULT_NZ(h);
TEST_MSG("%s\n", value->signal);
if (int status = _mon_check_props(h, value->attributes.size, value->attributes.direction, value->attributes.scalar, value->attributes.type)) return status;
if (value->children.size) {
int size = 0;
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, h);
while (TestVpiHandle word_h = vpi_scan(iter_h.nofree())) {
// check size and range
if (int status = _mon_check_props(word_h, value->children.size, value->children.direction, value->children.scalar, value->children.type)) return status;
size++;
}
CHECK_RESULT(size, value->attributes.size);
}
value++;
}
return 0;
}
int mon_check() {
// Callback from initial block in monitor
if (int status = mon_check_props()) return status;
return 0; // Ok
}
//======================================================================
#ifdef IS_VPI
static int mon_check_vpi() {
vpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {
vpi_compat_bootstrap,
0
};
#else
double sc_time_stamp () {
return main_time;
}
int main(int argc, char **argv, char **env) {
double sim_time = 1100;
Verilated::commandArgs(argc, argv);
Verilated::debug(0);
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
#ifdef VERILATOR
# ifdef TEST_VERBOSE
Verilated::scopesDump();
# endif
#endif
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
#if VM_TRACE
VL_PRINTF("Enabling waves...\n");
topp->trace (tfp, 99);
tfp->open ("obj_dir/t_vpi_var/simx.vcd");
#endif
topp->eval();
topp->clk = 0;
main_time += 10;
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += 1;
topp->eval();
VerilatedVpi::callValueCbs();
topp->clk = !topp->clk;
//mon_do();
#if VM_TRACE
if (tfp) tfp->dump (main_time);
#endif
}
if (!Verilated::gotFinish()) {
vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish");
}
topp->final();
#if VM_TRACE
if (tfp) tfp->close();
#endif
delete topp; topp=NULL;
exit(0L);
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2010 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 (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_get.cpp"],
make_pli => 1,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2 => ["+define+USE_VPI_NOT_DPI"],
);
execute (
iv_pli => 1,
check_finished=>1
);
ok(1);
1;
+71
View File
@@ -0,0 +1,71 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2010 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.
`ifdef USE_VPI_NOT_DPI
//We call it via $c so we can verify DPI isn't required - see bug572
`else
import "DPI-C" context function integer mon_check();
`endif
module t (/*AUTOARG*/
// Inputs
input clk /*verilator public_flat_rd */,
// test ports
input [15:0] testin /*verilator public_flat_rd */,
output [23:0] testout /*verilator public_flat_rw @(posedge clk) */
);
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
reg onebit /*verilator public_flat_rw @(posedge clk) */;
reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */;
reg onetwo [1:2] /*verilator public_flat_rw @(posedge clk) */;
reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */;
integer status;
`ifdef iverilog
// stop icarus optimizing signals away
wire redundant = onebit | onetwo[1] | twoone | fourthreetwoone[3];
`endif
wire subin /*verilator public_flat_rd*/;
wire subout /*verilator public_flat_rd*/;
sub sub(.*);
// Test loop
initial begin
`ifdef VERILATOR
status = $c32("mon_check()");
`endif
`ifdef iverilog
status = $mon_check();
`endif
`ifndef USE_VPI_NOT_DPI
status = mon_check();
`endif
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule : t
module sub (
input subin /*verilator public_flat_rd*/,
output subout /*verilator public_flat_rd*/
);
endmodule : sub
+267
View File
@@ -0,0 +1,267 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2010-2011 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.
//
//*************************************************************************
#ifdef IS_VPI
#include "vpi_user.h"
#include <cstdlib>
#else
#include "Vt_vpi_memory.h"
#include "verilated.h"
#include "svdpi.h"
#include "Vt_vpi_memory__Dpi.h"
#include "verilated_vpi.h"
#include "verilated_vpi.cpp"
#include "verilated_vcd_c.h"
#endif
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_memory.cpp"
#define DEBUG if (0) printf
unsigned int main_time = false;
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
FILENM,__LINE__, (got), (exp)); \
return __LINE__; \
}
#define CHECK_RESULT_NZ(got) \
if (!(got)) { \
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM,__LINE__); \
return __LINE__; \
}
// Use cout to avoid issues with %d/%lx etc
#define CHECK_RESULT(got, exp) \
if ((got != exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__ \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_HEX(got, exp) \
if ((got != exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__<<hex \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_CSTR(got, exp) \
if (strcmp((got),(exp))) { \
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", \
FILENM,__LINE__, (got)?(got):"<null>", (exp)?(exp):"<null>"); \
return __LINE__; \
}
#define CHECK_RESULT_CSTR_STRIP(got, exp) \
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
int _mon_check_range(TestVpiHandle& handle, int size, int left, int right) {
TestVpiHandle iter_h, left_h, right_h;
s_vpi_value value = {
vpiIntVal
};
// check size of object
int vpisize = vpi_get(vpiSize, handle);
CHECK_RESULT(vpisize, size);
// check size of range
vpisize = vpi_get(vpiSize, handle);
CHECK_RESULT(vpisize, size);
// check left hand side of range
left_h = vpi_handle(vpiLeftRange, handle);
CHECK_RESULT_NZ(left_h);
vpi_get_value(left_h, &value);
CHECK_RESULT(value.value.integer, left);
int coherency = value.value.integer;
// check right hand side of range
right_h = vpi_handle(vpiRightRange, handle);
CHECK_RESULT_NZ(right_h);
vpi_get_value(right_h, &value);
CHECK_RESULT(value.value.integer, right);
coherency -= value.value.integer;
// calculate size & check
coherency = abs(coherency) + 1;
CHECK_RESULT(coherency, size);
return 0; // Ok
}
int _mon_check_memory() {
int cnt;
TestVpiHandle mem_h, lcl_h;
vpiHandle iter_h; // icarus does not like auto free of iterator handles
s_vpi_value value = {
vpiIntVal
};
vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n");
mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("mem0"), NULL);
CHECK_RESULT_NZ(mem_h);
// check type
int vpitype = vpi_get(vpiType, mem_h);
CHECK_RESULT(vpitype, vpiMemory);
if (int status = _mon_check_range(mem_h, 16, 16, 1)) return status;
// iterate and store
iter_h = vpi_iterate(vpiMemoryWord, mem_h);
cnt = 0;
while (lcl_h = vpi_scan(iter_h)) {
value.value.integer = ++cnt;
vpi_put_value(lcl_h, &value, NULL, vpiNoDelay);
// check size and range
if (int status = _mon_check_range(lcl_h, 32, 31, 0)) return status;
}
CHECK_RESULT(cnt, 16); // should be 16 addresses
// iterate and accumulate
iter_h = vpi_iterate(vpiMemoryWord, mem_h);
cnt = 0;
while (lcl_h = vpi_scan(iter_h)) {
++cnt;
vpi_get_value(lcl_h, &value);
CHECK_RESULT(value.value.integer, cnt);
}
CHECK_RESULT(cnt, 16); // should be 16 addresses
// don't care for non verilator
// (crashes on Icarus)
if (TestSimulator::is_icarus()) {
vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", TestSimulator::get_info().product);
return 0; // Ok
}
// make sure trying to get properties that don't exist
// doesn't crash
int should_be_0 = vpi_get(vpiSize, iter_h);
CHECK_RESULT(should_be_0, 0);
should_be_0 = vpi_get(vpiIndex, iter_h);
CHECK_RESULT(should_be_0, 0);
vpiHandle should_be_NULL = vpi_handle(vpiLeftRange, iter_h);
CHECK_RESULT(should_be_NULL, 0);
should_be_NULL = vpi_handle(vpiRightRange, iter_h);
CHECK_RESULT(should_be_NULL, 0);
should_be_NULL = vpi_handle(vpiScope, iter_h);
CHECK_RESULT(should_be_NULL, 0);
return 0; // Ok
}
int mon_check() {
// Callback from initial block in monitor
if (int status = _mon_check_memory()) return status;
return 0; // Ok
}
//======================================================================
#ifdef IS_VPI
static int mon_check_vpi() {
vpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {
vpi_compat_bootstrap,
0
};
#else
double sc_time_stamp () {
return main_time;
}
int main(int argc, char **argv, char **env) {
double sim_time = 1100;
Verilated::commandArgs(argc, argv);
Verilated::debug(0);
Verilated::fatalOnVpiError(0); // we're going to be checking for these errors do don't crash out
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
#ifdef VERILATOR
# ifdef TEST_VERBOSE
Verilated::scopesDump();
# endif
#endif
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
#if VM_TRACE
VL_PRINTF("Enabling waves...\n");
topp->trace (tfp, 99);
tfp->open ("obj_dir/t_vpi_var/simx.vcd");
#endif
topp->eval();
topp->clk = 0;
main_time += 10;
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += 1;
topp->eval();
VerilatedVpi::callValueCbs();
topp->clk = !topp->clk;
//mon_do();
#if VM_TRACE
if (tfp) tfp->dump (main_time);
#endif
}
if (!Verilated::gotFinish()) {
vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish");
}
topp->final();
#if VM_TRACE
if (tfp) tfp->close();
#endif
delete topp; topp=NULL;
exit(0L);
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2010 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 (
make_top_shell => 0,
make_main => 0,
make_pli => 1,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2 => ["+define+USE_VPI_NOT_DPI"],
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_memory.cpp"],
);
execute (
iv_pli => 1,
check_finished=>1
);
ok(1);
1;
+58
View File
@@ -0,0 +1,58 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2010 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.
`ifdef USE_VPI_NOT_DPI
//We call it via $c so we can verify DPI isn't required - see bug572
`else
import "DPI-C" context function integer mon_check();
`endif
module t (/*AUTOARG*/
// Inputs
clk
);
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
input clk;
reg [31:0] mem0 [16:1] /*verilator public_flat_rw @(posedge clk) */;
integer i, status;
// Test loop
initial begin
`ifdef VERILATOR
status = $c32("mon_check()");
`endif
`ifdef iverilog
status = $mon_check();
`endif
`ifndef USE_VPI_NOT_DPI
status = mon_check();
`endif
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
for (i = 16; i > 0; i--)
if (mem0[i] !== i) begin
$write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i);
status = 1;
end
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule : t
+3 -15
View File
@@ -25,6 +25,8 @@
#include <iostream>
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_unimpl.cpp"
@@ -35,20 +37,6 @@ unsigned int callback_count = false;
//======================================================================
class VlVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
public:
VlVpiHandle() : m_handle(NULL) { }
VlVpiHandle(vpiHandle h) : m_handle(h) { }
~VlVpiHandle() { if (m_handle) { vpi_release_handle(m_handle); m_handle=NULL; } }
operator vpiHandle () const { return m_handle; }
inline VlVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
};
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
@@ -88,7 +76,7 @@ public:
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
int _mon_check_unimpl(p_cb_data cb_data) {
static VlVpiHandle cb, clk_h;
static TestVpiHandle cb, clk_h;
if (cb_data) {
// this is the callback
s_vpi_error_info info;
+129 -69
View File
@@ -13,6 +13,12 @@
//
//*************************************************************************
#ifdef IS_VPI
#include "vpi_user.h"
#else
#include "Vt_vpi_var.h"
#include "verilated.h"
#include "svdpi.h"
@@ -23,7 +29,16 @@
#include "verilated_vpi.cpp"
#include "verilated_vcd_c.h"
#endif
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_var.cpp"
@@ -39,20 +54,6 @@ unsigned int callback_count_strs_max = 500;
//======================================================================
class VlVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
public:
VlVpiHandle() : m_handle(NULL) { }
VlVpiHandle(vpiHandle h) : m_handle(h) { }
~VlVpiHandle() { if (m_handle) { vpi_release_handle(m_handle); m_handle=NULL; } }
operator vpiHandle () const { return m_handle; }
inline VlVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
};
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
@@ -93,7 +94,7 @@ public:
int _mon_check_mcd() {
PLI_INT32 status;
PLI_UINT32 mcd;
PLI_BYTE8* filename = (PLI_BYTE8*)"obj_dir/t_vpi_var/mcd_open.tmp";
mcd = vpi_mcd_open(filename);
@@ -112,7 +113,8 @@ int _mon_check_mcd() {
CHECK_RESULT(status, 0);
status = vpi_mcd_close(mcd);
CHECK_RESULT(status, 0);
// Icarus says 'error' on ones we're not using, so check only used ones return 0.
CHECK_RESULT(status & mcd, 0);
status = vpi_flush();
CHECK_RESULT(status, 0);
@@ -120,12 +122,18 @@ int _mon_check_mcd() {
return 0;
}
int _mon_check_callbacks_error(p_cb_data cb_data) {
vpi_printf((PLI_BYTE8*)"%%Error: callback should not be executed\n");
return 1;
}
int _mon_check_callbacks() {
t_cb_data cb_data;
cb_data.reason = cbEndOfSimulation;
cb_data.cb_rtn = NULL;
cb_data.cb_rtn = _mon_check_callbacks_error;
cb_data.user_data = 0;
cb_data.value = NULL;
cb_data.time = NULL;
vpiHandle vh = vpi_register_cb(&cb_data);
CHECK_RESULT_NZ(vh);
@@ -137,13 +145,20 @@ int _mon_check_callbacks() {
}
int _value_callback(p_cb_data cb_data) {
CHECK_RESULT(cb_data->value->value.integer+10, main_time);
if (TestSimulator::is_verilator()) {
// this check only makes sense in Verilator
CHECK_RESULT(cb_data->value->value.integer+10, main_time);
}
callback_count++;
return 0;
}
int _value_callback_half(p_cb_data cb_data) {
CHECK_RESULT(cb_data->value->value.integer*2+10, main_time);
if (TestSimulator::is_verilator()) {
// this check only makes sense in Verilator
CHECK_RESULT(cb_data->value->value.integer*2+10, main_time);
}
callback_count_half++;
return 0;
}
@@ -158,7 +173,7 @@ int _value_callback_quad(p_cb_data cb_data) {
}
int _mon_check_value_callbacks() {
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL);
vpiHandle vh1 = VPI_HANDLE("count");
CHECK_RESULT_NZ(vh1);
s_vpi_value v;
@@ -170,11 +185,12 @@ int _mon_check_value_callbacks() {
cb_data.cb_rtn = _value_callback;
cb_data.obj = vh1;
cb_data.value = &v;
cb_data.time = NULL;
vpiHandle vh = vpi_register_cb(&cb_data);
CHECK_RESULT_NZ(vh);
vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.half_count", NULL);
vh1 = VPI_HANDLE("half_count");
CHECK_RESULT_NZ(vh1);
cb_data.obj = vh1;
@@ -183,7 +199,7 @@ int _mon_check_value_callbacks() {
vh = vpi_register_cb(&cb_data);
CHECK_RESULT_NZ(vh);
vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.quads", NULL);
vh1 = VPI_HANDLE("quads");
CHECK_RESULT_NZ(vh1);
v.format = vpiVectorVal;
@@ -205,10 +221,10 @@ int _mon_check_value_callbacks() {
}
int _mon_check_var() {
VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL);
TestVpiHandle vh1 = VPI_HANDLE("onebit");
CHECK_RESULT_NZ(vh1);
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t", NULL);
TestVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::top(), NULL);
CHECK_RESULT_NZ(vh2);
// scope attributes
@@ -216,58 +232,60 @@ int _mon_check_var() {
p = vpi_get_str(vpiName, vh2);
CHECK_RESULT_CSTR(p, "t");
p = vpi_get_str(vpiFullName, vh2);
CHECK_RESULT_CSTR(p, "t");
CHECK_RESULT_CSTR(p, TestSimulator::top());
VlVpiHandle vh3 = vpi_handle_by_name((PLI_BYTE8*)"onebit", vh2);
TestVpiHandle vh3 = vpi_handle_by_name((PLI_BYTE8*)"onebit", vh2);
CHECK_RESULT_NZ(vh3);
// onebit attributes
PLI_INT32 d;
d = vpi_get(vpiType, vh3);
CHECK_RESULT(d, vpiReg);
d = vpi_get(vpiDirection, vh3);
CHECK_RESULT(d, vpiNoDirection);
d = vpi_get(vpiVector, vh3);
CHECK_RESULT(d, 0);
if (TestSimulator::has_get_scalar()) {
d = vpi_get(vpiVector, vh3);
CHECK_RESULT(d, 0);
}
p = vpi_get_str(vpiName, vh3);
CHECK_RESULT_CSTR(p, "onebit");
p = vpi_get_str(vpiFullName, vh3);
CHECK_RESULT_CSTR(p, "t.onebit");
CHECK_RESULT_CSTR(p, TestSimulator::rooted("onebit"));
// array attributes
VlVpiHandle vh4 = vpi_handle_by_name((PLI_BYTE8*)"t.fourthreetwoone", NULL);
TestVpiHandle vh4 = VPI_HANDLE("fourthreetwoone");
CHECK_RESULT_NZ(vh4);
d = vpi_get(vpiVector, vh4);
CHECK_RESULT(d, 1);
if (TestSimulator::has_get_scalar()) {
d = vpi_get(vpiVector, vh4);
CHECK_RESULT(d, 1);
}
t_vpi_value tmpValue;
tmpValue.format = vpiIntVal;
{
VlVpiHandle vh10 = vpi_handle(vpiLeftRange, vh4);
TestVpiHandle vh10 = vpi_handle(vpiLeftRange, vh4);
CHECK_RESULT_NZ(vh10);
vpi_get_value(vh10, &tmpValue);
CHECK_RESULT(tmpValue.value.integer,2);
CHECK_RESULT(tmpValue.value.integer,4);
}
{
VlVpiHandle vh10 = vpi_handle(vpiRightRange, vh4);
TestVpiHandle vh10 = vpi_handle(vpiRightRange, vh4);
CHECK_RESULT_NZ(vh10);
vpi_get_value(vh10, &tmpValue);
CHECK_RESULT(tmpValue.value.integer,1);
CHECK_RESULT(tmpValue.value.integer,3);
}
{
VlVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4);
TestVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4);
CHECK_RESULT_NZ(vh10);
VlVpiHandle vh11 = vpi_scan(vh10);
TestVpiHandle vh11 = vpi_scan(vh10);
CHECK_RESULT_NZ(vh11);
VlVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11);
TestVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11);
CHECK_RESULT_NZ(vh12);
vpi_get_value(vh12, &tmpValue);
CHECK_RESULT(tmpValue.value.integer,4);
VlVpiHandle vh13 = vpi_handle(vpiRightRange, vh11);
CHECK_RESULT(tmpValue.value.integer,2);
TestVpiHandle vh13 = vpi_handle(vpiRightRange, vh11);
CHECK_RESULT_NZ(vh13);
vpi_get_value(vh13, &tmpValue);
CHECK_RESULT(tmpValue.value.integer,3);
CHECK_RESULT(tmpValue.value.integer,1);
}
return 0;
@@ -276,30 +294,30 @@ int _mon_check_var() {
int _mon_check_varlist() {
const char* p;
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.sub", NULL);
TestVpiHandle vh2 = VPI_HANDLE("sub");
CHECK_RESULT_NZ(vh2);
VlVpiHandle vh10 = vpi_iterate(vpiReg, vh2);
CHECK_RESULT_NZ(vh10);
TestVpiHandle vh10 = vpi_iterate(vpiReg, vh2);
CHECK_RESULT_NZ(vh10.nofree());
VlVpiHandle vh11 = vpi_scan(vh10);
TestVpiHandle vh11 = vpi_scan(vh10);
CHECK_RESULT_NZ(vh11);
p = vpi_get_str(vpiFullName, vh11);
CHECK_RESULT_CSTR(p, "t.sub.subsig1");
CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig1"));
VlVpiHandle vh12 = vpi_scan(vh10);
TestVpiHandle vh12 = vpi_scan(vh10);
CHECK_RESULT_NZ(vh12);
p = vpi_get_str(vpiFullName, vh12);
CHECK_RESULT_CSTR(p, "t.sub.subsig2");
CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig2"));
VlVpiHandle vh13 = vpi_scan(vh10);
TestVpiHandle vh13 = vpi_scan(vh10);
CHECK_RESULT(vh13,0);
return 0;
}
int _mon_check_getput() {
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL);
TestVpiHandle vh2 = VPI_HANDLE("onebit");
CHECK_RESULT_NZ(vh2);
s_vpi_value v;
@@ -321,7 +339,7 @@ int _mon_check_getput() {
}
int _mon_check_quad() {
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.quads", NULL);
TestVpiHandle vh2 = VPI_HANDLE("quads");
CHECK_RESULT_NZ(vh2);
s_vpi_value v;
@@ -332,9 +350,9 @@ int _mon_check_quad() {
t.high = 0;
t.low = 0;
VlVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2);
TestVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2);
CHECK_RESULT_NZ(vhidx2);
VlVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3);
TestVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3);
CHECK_RESULT_NZ(vhidx2);
v.format = vpiVectorVal;
@@ -366,15 +384,15 @@ int _mon_check_string() {
const char *initial;
const char *value;
} text_test_obs[] = {
{"t.text_byte", "B", "xxA"}, // x's dropped
{"t.text_half", "Hf", "xxT2"}, // x's dropped
{"t.text_word", "Word", "Tree"},
{"t.text_long", "Long64b", "44Four44"},
{"t.text" , "Verilog Test module", "lorem ipsum"},
{"text_byte", "B", "xxA"}, // x's dropped
{"text_half", "Hf", "xxT2"}, // x's dropped
{"text_word", "Word", "Tree"},
{"text_long", "Long64b", "44Four44"},
{"text" , "Verilog Test module", "lorem ipsum"},
};
for (int i=0; i<5; i++) {
VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)text_test_obs[i].name, NULL);
TestVpiHandle vh1 = VPI_HANDLE(text_test_obs[i].name);
CHECK_RESULT_NZ(vh1);
s_vpi_value v;
@@ -397,9 +415,9 @@ int _mon_check_string() {
}
int _mon_check_putget_str(p_cb_data cb_data) {
static VlVpiHandle cb;
static TestVpiHandle cb;
static struct {
VlVpiHandle scope, sig, rfr, check, verbose;
TestVpiHandle scope, sig, rfr, check, verbose;
char str[128+1]; // char per bit plus null terminator
int type; // value type in .str
union {
@@ -492,7 +510,7 @@ int _mon_check_putget_str(p_cb_data cb_data) {
// setup and install
for (int i=1; i<=128; i++) {
char buf[32];
snprintf(buf, sizeof(buf), "t.arr[%d].arr", i);
snprintf(buf, sizeof(buf), TestSimulator::rooted("arr[%d].arr"), i);
CHECK_RESULT_NZ(data[i].scope = vpi_handle_by_name((PLI_BYTE8*)buf, NULL));
CHECK_RESULT_NZ(data[i].sig = vpi_handle_by_name((PLI_BYTE8*)"sig", data[i].scope));
CHECK_RESULT_NZ(data[i].rfr = vpi_handle_by_name((PLI_BYTE8*)"rfr", data[i].scope));
@@ -502,12 +520,13 @@ int _mon_check_putget_str(p_cb_data cb_data) {
static t_cb_data cb_data;
static s_vpi_value v;
static VlVpiHandle count_h = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL);
static TestVpiHandle count_h = VPI_HANDLE("count");
cb_data.reason = cbValueChange;
cb_data.cb_rtn = _mon_check_putget_str; // this function
cb_data.obj = count_h;
cb_data.value = &v;
cb_data.time = NULL;
v.format = vpiIntVal;
cb = vpi_register_cb(&cb_data);
@@ -524,12 +543,15 @@ int _mon_check_vlog_info() {
CHECK_RESULT_CSTR(vlog_info.argv[1], "+PLUS");
CHECK_RESULT_CSTR(vlog_info.argv[2], "+INT=1234");
CHECK_RESULT_CSTR(vlog_info.argv[3], "+STRSTR");
CHECK_RESULT_CSTR(vlog_info.product, "Verilator");
CHECK_RESULT(strlen(vlog_info.version) > 0, 1);
if (TestSimulator::is_verilator()) {
CHECK_RESULT_CSTR(vlog_info.product, "Verilator");
CHECK_RESULT(strlen(vlog_info.version) > 0, 1);
}
return 0;
}
#ifndef IS_VPI
#define CHECK_ENUM_STR(fn, enum) \
do { \
const char* strVal = VerilatedVpiError::fn(enum); \
@@ -567,6 +589,8 @@ int _mon_check_vl_str() {
return 0;
}
#endif
int mon_check() {
// Callback from initial block in monitor
if (int status = _mon_check_mcd()) return status;
@@ -579,12 +603,46 @@ int mon_check() {
if (int status = _mon_check_string()) return status;
if (int status = _mon_check_putget_str(NULL)) return status;
if (int status = _mon_check_vlog_info()) return status;
#ifndef IS_VPI
if (int status = _mon_check_vl_str()) return status;
#endif
return 0; // Ok
}
//======================================================================
#ifdef IS_VPI
static int mon_check_vpi() {
vpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {
vpi_compat_bootstrap,
0
};
#else
double sc_time_stamp () {
return main_time;
@@ -640,3 +698,5 @@ int main(int argc, char **argv, char **env) {
delete topp; topp=NULL;
exit(0L);
}
#endif
+5
View File
@@ -10,10 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
make_top_shell => 0,
make_main => 0,
make_pli => 1,
sim_time => 2100,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES"],
v_flags2 => ["+define+USE_VPI_NOT_DPI"],
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_var.cpp"],
);
execute (
iv_pli => 1,
check_finished=>1,
all_run_flags => ['+PLUS +INT=1234 +STRSTR']
);
+22 -6
View File
@@ -5,7 +5,7 @@
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
`ifdef VERILATOR
`ifdef USE_VPI_NOT_DPI
//We call it via $c so we can verify DPI isn't required - see bug572
`else
import "DPI-C" context function integer mon_check();
@@ -45,7 +45,9 @@ extern "C" int mon_check();
// Test loop
initial begin
count = 0;
onebit = 1'b0;
fourthreetwoone[3] = 0; // stop icarus optimizing away
text_byte = "B";
text_half = "Hf";
text_word = "Word";
@@ -53,13 +55,18 @@ extern "C" int mon_check();
text = "Verilog Test module";
`ifdef VERILATOR
status = $c32("mon_check()");
`else
status = mon_check();
`endif
`ifdef iverilog
status = $mon_check();
`endif
`ifndef USE_VPI_NOT_DPI
status = mon_check();
`endif
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("%%Info: Checking results\n");
if (onebit != 1'b1) $stop;
if (quads[2] != 62'h12819213_abd31a1c) $stop;
if (quads[3] != 62'h1c77bb9b_3784ea09) $stop;
@@ -83,16 +90,20 @@ extern "C" int mon_check();
genvar i;
generate
for (i=1;i<=128;i++) begin : arr
for (i=1; i<=128; i=i+1) begin : arr
arr #(.LENGTH(i)) arr();
end endgenerate
endmodule
endmodule : t
module sub;
reg subsig1 /*verilator public_flat_rd*/;
reg subsig2 /*verilator public_flat_rd*/;
endmodule
`ifdef iverilog
// stop icarus optimizing signals away
wire redundant = subsig1 | subsig2;
`endif
endmodule : sub
module arr;
@@ -104,6 +115,11 @@ module arr;
reg check /*verilator public_flat_rw*/;
reg verbose /*verilator public_flat_rw*/;
initial begin
sig = {LENGTH{1'b0}};
rfr = {LENGTH{1'b0}};
end
always @(posedge check) begin
if (verbose) $display("%m : %x %x", sig, rfr);
if (check && sig != rfr) $stop;