mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e1fcd38bb | ||
|
|
e74186565d | ||
|
|
7e54281e26 | ||
|
|
15f512bdee | ||
|
|
ecfe0283e2 | ||
|
|
3b874f759c | ||
|
|
9c9b4ed4e0 | ||
|
|
4f6d80c602 | ||
|
|
b50542531d | ||
|
|
8ab28d1d12 | ||
|
|
9567da22f8 | ||
|
|
36814b7681 | ||
|
|
82235e6c6f | ||
|
|
a8310f35f2 | ||
|
|
85989af031 | ||
|
|
cf9ffd16dd | ||
|
|
0602537cce | ||
|
|
24e32420b7 | ||
|
|
39c494260b | ||
|
|
761b9c9290 | ||
|
|
27686d8c2f | ||
|
|
d2b007005d | ||
|
|
f1ef30a5bb | ||
|
|
f1d9437c55 | ||
|
|
bcba5075e8 | ||
|
|
d6e8b0263c | ||
|
|
9aba617bad | ||
|
|
c24f7b1391 | ||
|
|
d4e27b635f | ||
|
|
c996d2870c | ||
|
|
bbd59f8a22 | ||
|
|
d3d359e757 | ||
|
|
ae763ea93d | ||
|
|
236b9e9761 | ||
|
|
e42c9dfd84 | ||
|
|
bebf5b291b | ||
|
|
1e3dcd203d | ||
|
|
cc7da63dec | ||
|
|
1baa2a2558 | ||
|
|
e63ff77b15 | ||
|
|
6cf9468477 | ||
|
|
b277bc8750 | ||
|
|
ba9da64207 | ||
|
|
9cb9f9c80b |
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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";
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
Executable
+19
@@ -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;
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+19
@@ -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;
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+55
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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},
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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 .*},
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+20
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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.*',
|
||||
);
|
||||
|
||||
|
||||
@@ -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.*',
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Executable
+25
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Executable
+25
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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']
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user