Compare commits

...
22 Commits
Author SHA1 Message Date
Wilson Snyder 0e1fcd38bb Version bump 2013-11-26 19:52:19 -05:00
Wilson Snyder e74186565d Add --compiler clang to work around compiler bug, bug694. 2013-11-26 18:46:55 -05:00
Wilson Snyder 7e54281e26 Fix array assignment from const var, bug693. 2013-10-31 22:39:26 -04:00
Wilson Snyder 15f512bdee Debug: With --debug, run check tree at all steps even if no --dump-more 2013-10-30 23:25:54 -04:00
Wilson Snyder ecfe0283e2 Fix crash with coverage of structures, bug691. 2013-10-29 20:15:01 -04:00
Wilson Snyder 3b874f759c Fix of last commit, bug689. 2013-10-28 21:57:52 -04:00
Wilson Snyder 9c9b4ed4e0 Fix vpi_remove_cb inside callback, bug689. 2013-10-28 21:00:40 -04:00
Wilson Snyder 4f6d80c602 Add UNPACKED warning to convert unpacked structs. 2013-10-28 20:41:05 -04:00
Wilson Snyder b50542531d Fix enum value extension of '1. 2013-10-28 20:24:31 -04:00
Wilson Snyder 8ab28d1d12 Merge branch 'master' of ssh://git-verilator-wsnyder/git/verilator 2013-10-28 11:15:33 -04:00
Wilson Snyder 9567da22f8 Compiler warning fix. 2013-10-28 11:14:13 -04:00
Wilson Snyder 36814b7681 Support vpi_get_time, bug688. 2013-10-22 22:02:53 -04:00
Wilson Snyder 82235e6c6f Fix vpi_get of vpiSuppressVal, bug687. 2013-10-22 22:01:19 -04:00
Wilson Snyder a8310f35f2 Fix evaluation of chained parameter functions, bug684. 2013-10-18 07:06:32 -04:00
Rich Porter 85989af031 Fix vpi_get of vpiSize, bug680.
Signed-off-by: Wilson Snyder <[email protected]>
2013-10-13 20:05:57 -04:00
Rich Porter cf9ffd16dd tests: For icarus, exit on stop. Merge from RPORTER/vpi-vpiSize-680.
Signed-off-by: Wilson Snyder <[email protected]>
2013-10-11 21:34:48 -04:00
Wilson Snyder 0602537cce Fix t/t_select_index2 test. 2013-10-11 21:29:54 -04:00
Wilson Snyder 24e32420b7 Fix multiple VPI variable callbacks, bug679. 2013-10-03 07:24:50 -04:00
Wilson Snyder 39c494260b devel release 2013-09-30 16:56:52 -04:00
Wilson Snyder 761b9c9290 Version bump 2013-09-30 16:53:45 -04:00
Wilson Snyder 27686d8c2f Add --no-order-clock-delay to work around bug613. 2013-09-30 16:52:43 -04:00
Wilson Snyder d2b007005d devel release 2013-09-29 20:56:19 -04:00
45 changed files with 1275 additions and 254 deletions
+30
View File
@@ -3,6 +3,36 @@ 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]
+20
View File
@@ -299,6 +299,7 @@ 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 .cpp functions
--output-split-ctrace <statements> Split tracing functions
@@ -468,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
@@ -789,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
@@ -3218,6 +3231,13 @@ section for more details.
Ignoring this warning will only slow simulations, it will simulate
correctly.
=item UNPACKED
Warns that unpacked structs and unions are not supported.
Ignoring this warning will make Verilator treat the structure as packed,
which may make Verilator simulations differ from other simulators.
=item UNSIGNED
Warns that you are comparing a unsigned value in a way that implies it is
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.852 2013-09-29])
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)
+1
View File
@@ -770,6 +770,7 @@ void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
}
void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...) {
if (obits_ignored) {}
output = "";
va_list ap;
va_start(ap,formatp);
+57 -22
View File
@@ -38,7 +38,7 @@
// Internal macros
#define _VL_VPI_INTERNAL VerilatedVpi::error_info()->setMessage(vpiInternal)->setMessage
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
#define _VL_VPI_ERROR VerilatedVpi::error_info()->setMessage(vpiError )->setMessage
#define _VL_VPI_WARNING VerilatedVpi::error_info()->setMessage(vpiWarning )->setMessage
#define _VL_VPI_NOTICE VerilatedVpi::error_info()->setMessage(vpiNotice )->setMessage
@@ -52,6 +52,8 @@
// Implementation
#include <set>
#include <list>
#include <map>
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
#define VL_VPI_LINE_SIZE 8192
@@ -180,6 +182,10 @@ 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) {
@@ -198,10 +204,12 @@ public:
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() { return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */ }
virtual const vluint32_t size() { return range().elements(); }
const VerilatedRange& range() { return m_varp->dims()?m_varp->array():m_varp->range(); }
virtual const VerilatedRange* rangep() { return &range(); }
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;
@@ -301,7 +309,7 @@ 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;
struct product_info {
@@ -309,7 +317,7 @@ class VerilatedVpi {
PLI_BYTE8* version;
};
VpioCbSet m_cbObjSets[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
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
@@ -325,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) {
@@ -364,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
@@ -386,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
@@ -1006,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());
@@ -1297,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
+2 -2
View File
@@ -1016,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));
+5 -1
View File
@@ -1160,7 +1160,7 @@ public:
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
@@ -1542,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; }
@@ -1591,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 {
@@ -1645,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;
+13 -3
View File
@@ -227,6 +227,7 @@ public:
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
virtual string name() const { return m_name; }
@@ -368,6 +369,7 @@ public:
// METHODS
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead
@@ -427,7 +429,8 @@ public:
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
@@ -456,6 +459,7 @@ public:
virtual void cloneRelink();
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
@@ -506,6 +510,10 @@ public:
if (defp()) return defp()->skipRefp();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual AstNodeDType* skipRefToConstp() const {
if (defp()) return defp()->skipRefToConstp();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) { m_name = flag; }
@@ -573,7 +581,8 @@ public:
//
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
virtual AstNodeDType* skipRefp() const { return dtypeSkipRefp(); }
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// METHODS
@@ -662,6 +671,7 @@ public:
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
@@ -961,7 +971,7 @@ public:
void combineType(AstVarType type);
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
+1 -1
View File
@@ -89,7 +89,7 @@ private:
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
bool isArray = arrayp;
bool isStruct = structp && structp->packed();
bool isStruct = structp && structp->packedUnsup();
int elements = isArray ? arrayp->elementsConst() : 1;
if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
+45 -1
View File
@@ -213,7 +213,7 @@ private:
}
}
else if (AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) {
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code),
@@ -224,6 +224,50 @@ private:
newent.cleanup();
}
}
else if (AstPackArrayDType* adtypep = dtypep->castPackArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb(); ++index_docs) {
AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp();
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
index_code*subtypep->width(), subtypep->width()),
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true),
index_code*subtypep->width(), subtypep->width()));
toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else if (AstStructDType* adtypep = dtypep->castStructDType()) {
// For now it's packed, so similar to array
for (AstMemberDType* itemp = adtypep->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
int index_code = itemp->lsb();
ToggleEnt newent (above.m_comment+string(".")+itemp->name(),
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
index_code, subtypep->width()),
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true),
index_code, subtypep->width()));
toggleVarRecurse(subtypep, depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else if (AstUnionDType* adtypep = dtypep->castUnionDType()) {
// Arbitrarially handle only the first member of the union
if (AstMemberDType* itemp = adtypep->membersp()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent (above.m_comment+string(".")+itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true));
toggleVarRecurse(subtypep, depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
else {
dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<<dtypep->prettyTypeName());
}
+2 -1
View File
@@ -93,6 +93,7 @@ public:
UNDRIVEN, // No drivers
UNOPT, // Unoptimizable block
UNOPTFLAT, // Unoptimizable block after flattening
UNPACKED, // Unsupported unpacked
UNSIGNED, // Comparison is constant due to unsigned arithmetic
UNUSED, // No receivers
VARHIDDEN, // Hiding variable
@@ -129,7 +130,7 @@ public:
"PINMISSING", "PINNOCONNECT",
"REALCVT", "REDEFMACRO",
"SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNPACKED", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
" MAX"
};
+1 -1
View File
@@ -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) {
+6 -1
View File
@@ -738,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; }
@@ -962,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
@@ -1203,6 +1207,7 @@ V3Options::V3Options() {
m_lintOnly = false;
m_makeDepend = true;
m_makePhony = false;
m_orderClockDly = true;
m_outFormatOk = false;
m_warnFatal = true;
m_pinsBv = 65;
+2
View File
@@ -74,6 +74,7 @@ class V3Options {
bool m_inhibitSim; // main switch: --inhibit-sim
bool m_l2Name; // main switch: --l2name
bool m_lintOnly; // main switch: --lint-only
bool m_orderClockDly;// main switch: --order-clock-delay
bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified
bool m_warnFatal; // main switch: --warnFatal
bool m_pinsScUint; // main switch: --pins-sc-uint
@@ -214,6 +215,7 @@ class V3Options {
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool traceUnderscore() const { return m_traceUnderscore; }
bool orderClockDly() const { return m_orderClockDly; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool warnFatal() const { return m_warnFatal; }
+5 -1
View File
@@ -1161,7 +1161,11 @@ void OrderVisitor::processCircular() {
// 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 (vvertexp->isDelayed()) {
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);
}
+9 -4
View File
@@ -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->exprp();
if (pinp==NULL) {
// Too few arguments in function call - ignore it
} else {
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));
+10 -4
View File
@@ -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
@@ -1088,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
@@ -2251,12 +2253,16 @@ private:
void widthCheck (AstNode* nodep, const char* side,
AstNode* underp, AstNodeDType* expDTypep,
bool ignoreWarn=false) {
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e="<<expDTypep<<" i"<<ignoreWarn<<endl);
int expWidth = expDTypep->width();
int expWidthMin = expDTypep->widthMin();
if (expWidthMin==0) expWidthMin = expWidth;
bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if ((bad || underp->width() !=expWidth)
&& fixAutoExtend(underp/*ref*/,expWidth)) {
underp=NULL; // Changes underp
return;
}
if (underp->castConst() && underp->castConst()->num().isFromString()
&& expWidth > underp->width()
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
+1 -1
View File
@@ -389,7 +389,7 @@ private:
VNumRange fromRange = fromdata.m_fromRange;
if (ddtypep->castBasicDType()
|| (ddtypep->castNodeClassDType()
&& ddtypep->castNodeClassDType()->packed())) {
&& ddtypep->castNodeClassDType()->packedUnsup())) {
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (fromRange.littleEndian()) {
+78 -78
View File
@@ -141,8 +141,8 @@ void V3Global::readFiles() {
}
}
void V3Global::dumpGlobalTree(const string& filename, int newNumber) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(filename, newNumber));
void V3Global::dumpCheckGlobalTree(const string& filename, int newNumber, bool doDump) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename(filename, newNumber), false, doDump);
}
//######################################################################
@@ -152,26 +152,26 @@ void process () {
// Sort modules by level so later algorithms don't need to care
V3LinkLevel::modSortByLevel();
V3Global::dumpGlobalTree("cells.tree");
V3Global::dumpCheckGlobalTree("cells.tree");
V3Error::abortIfErrors();
// Convert parseref's to varrefs, and other directly post parsing fixups
V3LinkParse::linkParse(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkparse.tree");
V3Global::dumpCheckGlobalTree("linkparse.tree", 0, dumpMore);
// Cross-link signal names
// Cross-link dotted hierarchical references
V3LinkDot::linkDotPrimary(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree", 0, dumpMore);
v3Global.checkTree(); // Force a check, as link is most likely place for problems
// Correct state we couldn't know at parse time, repair SEL's
V3LinkResolve::linkResolve(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linkresolve.tree");
V3Global::dumpCheckGlobalTree("linkresolve.tree", 0, dumpMore);
// Set Lvalue's in variable refs
V3LinkLValue::linkLValue(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("linklvalue.tree");
V3Global::dumpCheckGlobalTree("linklvalue.tree", 0, dumpMore);
// Convert return/continue/disable to jumps
V3LinkJump::linkJump(v3Global.rootp());
V3Global::dumpGlobalTree("link.tree");
V3Global::dumpCheckGlobalTree("link.tree");
V3Error::abortIfErrors();
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link");
@@ -179,19 +179,19 @@ void process () {
// Remove parameters by cloning modules to de-parameterized versions
// This requires some width calculations and constant propagation
V3Param::param(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("param.tree");
V3Global::dumpCheckGlobalTree("param.tree", 0, dumpMore);
V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules
V3Global::dumpGlobalTree("paramlink.tree");
V3Global::dumpCheckGlobalTree("paramlink.tree");
V3Error::abortIfErrors();
// Remove any modules that were parameterized and are no longer referenced.
V3Dead::deadifyModules(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("dead.tree");
V3Global::dumpCheckGlobalTree("dead.tree", 0, dumpMore);
v3Global.checkTree();
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
V3Width::width(v3Global.rootp());
V3Global::dumpGlobalTree("width.tree");
V3Global::dumpCheckGlobalTree("width.tree");
V3Error::abortIfErrors();
@@ -199,19 +199,19 @@ void process () {
V3Width::widthCommit(v3Global.rootp());
v3Global.assertDTypesResolved(true);
v3Global.assertWidthsMatch(true);
if (dumpMore) V3Global::dumpGlobalTree("widthcommit.tree");
V3Global::dumpCheckGlobalTree("widthcommit.tree", 0, dumpMore);
// Coverage insertion
// Before we do dead code elimination and inlining, or we'll lose it.
if (v3Global.opt.coverage()) {
V3Coverage::coverage(v3Global.rootp());
V3Global::dumpGlobalTree("coverage.tree");
V3Global::dumpCheckGlobalTree("coverage.tree");
}
// Push constants, but only true constants preserving liveness
// so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..."
V3Const::constifyAllLive(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Signal based lint checks, no change to structures
// Must be before first constification pass drops dead code
@@ -220,10 +220,10 @@ void process () {
// Assertion insertion
// After we've added block coverage, but before other nasty transforms
V3AssertPre::assertPreAll(v3Global.rootp());
V3Global::dumpGlobalTree("assertpre.tree");
V3Global::dumpCheckGlobalTree("assertpre.tree");
//
V3Assert::assertAll(v3Global.rootp());
V3Global::dumpGlobalTree("assert.tree");
V3Global::dumpCheckGlobalTree("assert.tree");
if (!v3Global.opt.xmlOnly()) {
// Add top level wrapper with instance pointing to old top
@@ -234,38 +234,38 @@ void process () {
// Propagate constants into expressions
V3Const::constifyAllLint(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
if (!v3Global.opt.xmlOnly()) {
// Remove cell arrays (must be between V3Width and scoping)
V3Inst::dearrayAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("dearray.tree");
V3Global::dumpCheckGlobalTree("dearray.tree", 0, dumpMore);
}
if (!v3Global.opt.xmlOnly()) {
// Expand inouts, stage 2
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
V3Tristate::tristateAll(v3Global.rootp());
V3Global::dumpGlobalTree("tristate.tree");
V3Global::dumpCheckGlobalTree("tristate.tree");
// Task inlining & pushing BEGINs names to variables/cells
// Begin processing must be after Param, before module inlining
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
V3Global::dumpGlobalTree("begin.tree");
V3Global::dumpCheckGlobalTree("begin.tree");
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
V3Global::dumpGlobalTree("unknown.tree");
V3Global::dumpCheckGlobalTree("unknown.tree");
// Module inlining
// Cannot remove dead variables after this, as alias information for final
// V3Scope's V3LinkDot is in the AstVar.
if (v3Global.opt.oInline()) {
V3Inline::inlineAll(v3Global.rootp());
V3Global::dumpGlobalTree("inline.tree");
V3Global::dumpCheckGlobalTree("inline.tree");
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
if (dumpMore) V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree", 0, dumpMore);
}
}
@@ -273,11 +273,11 @@ void process () {
// Initial const/dead to reduce work for ordering code
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
v3Global.checkTree();
V3Dead::deadifyDTypes(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
v3Global.checkTree();
V3Error::abortIfErrors();
@@ -290,17 +290,17 @@ void process () {
// Convert instantiations to wassigns and always blocks
V3Inst::instAll(v3Global.rootp());
V3Global::dumpGlobalTree("inst.tree");
V3Global::dumpCheckGlobalTree("inst.tree");
// Inst may have made lots of concats; fix them
V3Const::constifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
V3Scope::scopeAll(v3Global.rootp());
V3Global::dumpGlobalTree("scope.tree");
V3Global::dumpCheckGlobalTree("scope.tree");
V3LinkDot::linkDotScope(v3Global.rootp());
V3Global::dumpGlobalTree("linkdot.tree");
V3Global::dumpCheckGlobalTree("linkdot.tree");
}
//--SCOPE BASED OPTIMIZATIONS--------------
@@ -308,87 +308,87 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Cleanup
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyDTypes(v3Global.rootp());
v3Global.checkTree();
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Convert case statements to if() blocks. Must be after V3Unknown
// Must be before V3Task so don't need to deal with task in case value compares
V3Case::caseAll(v3Global.rootp());
V3Global::dumpGlobalTree("case.tree");
V3Global::dumpCheckGlobalTree("case.tree");
// Inline all tasks
V3Task::taskAll(v3Global.rootp());
V3Global::dumpGlobalTree("task.tree");
V3Global::dumpCheckGlobalTree("task.tree");
// Add __PVT's
// After V3Task so task internal variables will get renamed
V3Name::nameAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("name.tree");
V3Global::dumpCheckGlobalTree("name.tree", 0, dumpMore);
// Loop unrolling & convert FORs to WHILEs
V3Unroll::unrollAll(v3Global.rootp());
V3Global::dumpGlobalTree("unroll.tree");
V3Global::dumpCheckGlobalTree("unroll.tree");
// Expand slices of arrays
V3Slice::sliceAll(v3Global.rootp());
V3Global::dumpGlobalTree("slices.tree");
V3Global::dumpCheckGlobalTree("slices.tree");
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
V3Global::dumpGlobalTree("life.tree");
V3Global::dumpCheckGlobalTree("life.tree");
}
// Make large low-fanin logic blocks into lookup tables
// This should probably be done much later, once we have common logic elimination.
if (!v3Global.opt.lintOnly() && v3Global.opt.oTable()) {
V3Table::tableAll(v3Global.rootp());
V3Global::dumpGlobalTree("table.tree");
V3Global::dumpCheckGlobalTree("table.tree");
}
// Cleanup
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyDTypes(v3Global.rootp());
v3Global.checkTree();
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Detect clock enables and mode into sensitives, and split always based on clocks
// (so this is a good prelude to splitAlways.)
if (v3Global.opt.oFlopGater()) {
V3ClkGater::clkGaterAll(v3Global.rootp());
V3Global::dumpGlobalTree("clkgater.tree");
V3Global::dumpCheckGlobalTree("clkgater.tree");
}
// Move assignments/sensitives into a SBLOCK for each unique sensitivity list
// (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
V3Active::activeAll(v3Global.rootp());
V3Global::dumpGlobalTree("active.tree");
V3Global::dumpCheckGlobalTree("active.tree");
// Split single ALWAYS blocks into multiple blocks for better ordering chances
if (v3Global.opt.oSplit()) {
V3Split::splitAlwaysAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("split.tree");
V3Global::dumpCheckGlobalTree("split.tree", 0, dumpMore);
}
V3SplitAs::splitAsAll(v3Global.rootp());
V3Global::dumpGlobalTree("splitas.tree");
V3Global::dumpCheckGlobalTree("splitas.tree");
// Create tracing sample points, before we start eliminating signals
if (v3Global.opt.trace()) {
V3TraceDecl::traceDeclAll(v3Global.rootp());
V3Global::dumpGlobalTree("tracedecl.tree");
V3Global::dumpCheckGlobalTree("tracedecl.tree");
}
// Gate-based logic elimination; eliminate signals and push constant across cell boundaries
// Instant propagation makes lots-o-constant reduction possibilities.
if (v3Global.opt.oGate()) {
V3Gate::gateAll(v3Global.rootp());
V3Global::dumpGlobalTree("gate.tree");
V3Global::dumpCheckGlobalTree("gate.tree");
// V3Gate calls constant propagation itself.
} else {
v3info("Command Line disabled gate optimization with -Og/-O0. This may cause ordering problems.");
@@ -397,14 +397,14 @@ void process () {
// Combine COVERINCs with duplicate terms
if (v3Global.opt.coverage()) {
V3CoverageJoin::coverageJoin(v3Global.rootp());
V3Global::dumpGlobalTree("coveragejoin.tree");
V3Global::dumpCheckGlobalTree("coveragejoin.tree");
}
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Clock domain crossing analysis
if (v3Global.opt.cdc()) {
@@ -416,34 +416,34 @@ void process () {
// Reorder assignments in pipelined blocks
if (v3Global.opt.oReorder()) {
V3Split::splitReorderAll(v3Global.rootp());
V3Global::dumpGlobalTree("reorder.tree");
V3Global::dumpCheckGlobalTree("reorder.tree");
}
// Create delayed assignments
// This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
V3Delayed::delayedAll(v3Global.rootp());
V3Global::dumpGlobalTree("delayed.tree");
V3Global::dumpCheckGlobalTree("delayed.tree");
// Make Active's on the top level
// Differs from V3Active, because identical clocks may be pushed down to a module and now be identical
V3ActiveTop::activeTopAll(v3Global.rootp());
V3Global::dumpGlobalTree("activetop.tree");
V3Global::dumpCheckGlobalTree("activetop.tree");
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
// Order the code; form SBLOCKs and BLOCKCALLs
V3Order::orderAll(v3Global.rootp());
V3Global::dumpGlobalTree("order.tree");
V3Global::dumpCheckGlobalTree("order.tree");
#ifndef NEW_ORDERING
// Change generated clocks to look at delayed signals
V3GenClk::genClkAll(v3Global.rootp());
V3Global::dumpGlobalTree("genclk.tree");
V3Global::dumpCheckGlobalTree("genclk.tree");
#endif
// Convert sense lists into IF statements.
V3Clock::clockAll(v3Global.rootp());
V3Global::dumpGlobalTree("clock.tree");
V3Global::dumpCheckGlobalTree("clock.tree");
// Cleanup any dly vars or other temps that are simple assignments
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
@@ -455,19 +455,19 @@ void process () {
V3LifePost::lifepostAll(v3Global.rootp());
}
if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
V3Global::dumpGlobalTree("life.tree");
V3Global::dumpCheckGlobalTree("life.tree");
}
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
#ifndef NEW_ORDERING
// Detect change loop
V3Changed::changedAll(v3Global.rootp());
V3Global::dumpGlobalTree("changed.tree");
V3Global::dumpCheckGlobalTree("changed.tree");
#endif
// Create tracing logic, since we ripped out some signals the user might want to trace
@@ -475,14 +475,14 @@ void process () {
// (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
if (v3Global.opt.trace()) {
V3Trace::traceAll(v3Global.rootp());
V3Global::dumpGlobalTree("trace.tree");
V3Global::dumpCheckGlobalTree("trace.tree");
}
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");
// Remove scopes; make varrefs/funccalls relative to current module
V3Descope::descopeAll(v3Global.rootp());
V3Global::dumpGlobalTree("descope.tree");
V3Global::dumpCheckGlobalTree("descope.tree");
}
//--MODULE OPTIMIZATIONS--------------
@@ -491,19 +491,19 @@ void process () {
// Split deep blocks to appease MSVC++. Must be before Localize.
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
V3DepthBlock::depthBlockAll(v3Global.rootp());
V3Global::dumpGlobalTree("deepblock.tree");
V3Global::dumpCheckGlobalTree("deepblock.tree");
}
// Move BLOCKTEMPS from class to local variables
if (v3Global.opt.oLocalize()) {
V3Localize::localizeAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("localize.tree");
V3Global::dumpCheckGlobalTree("localize.tree", 0, dumpMore);
}
// Icache packing; combine common code in each module's functions into subroutines
if (v3Global.opt.oCombine()) {
V3Combine::combineAll(v3Global.rootp());
V3Global::dumpGlobalTree("combine.tree");
V3Global::dumpCheckGlobalTree("combine.tree");
}
}
@@ -514,9 +514,9 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Remove unused vars
V3Const::constifyAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("const_predead.tree");
V3Global::dumpCheckGlobalTree("const_predead.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
// Here down, widthMin() is the Verilog width, and width() is the C++ width
// Bits between widthMin() and width() are irrelevant, but may be non zero.
@@ -524,18 +524,18 @@ void process () {
// Make all math operations either 8, 16, 32 or 64 bits
V3Clean::cleanAll(v3Global.rootp());
V3Global::dumpGlobalTree("clean.tree");
V3Global::dumpCheckGlobalTree("clean.tree");
// Move wide constants to BLOCK temps.
V3Premit::premitAll(v3Global.rootp());
V3Global::dumpGlobalTree("premit.tree");
V3Global::dumpCheckGlobalTree("premit.tree");
}
// Expand macros and wide operators into C++ primitives
if (!v3Global.opt.xmlOnly()
&& v3Global.opt.oExpand()) {
V3Expand::expandAll(v3Global.rootp());
V3Global::dumpGlobalTree("expand.tree");
V3Global::dumpCheckGlobalTree("expand.tree");
}
// Propagate constants across WORDSEL arrayed temporaries
@@ -543,18 +543,18 @@ void process () {
&& v3Global.opt.oSubst()) {
// Constant folding of expanded stuff
V3Const::constifyCpp(v3Global.rootp());
V3Global::dumpGlobalTree("const.tree");
V3Global::dumpCheckGlobalTree("const.tree");
V3Subst::substituteAll(v3Global.rootp());
V3Global::dumpGlobalTree("subst.tree");
V3Global::dumpCheckGlobalTree("subst.tree");
}
if (!v3Global.opt.xmlOnly()
&& v3Global.opt.oSubstConst()) {
// Constant folding of substitutions
V3Const::constifyCpp(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("constc.tree");
V3Global::dumpCheckGlobalTree("constc.tree", 0, dumpMore);
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpGlobalTree("dead.tree");
V3Global::dumpCheckGlobalTree("dead.tree");
}
if (!v3Global.opt.lintOnly()
@@ -562,7 +562,7 @@ void process () {
// Fix very deep expressions
// Mark evaluation functions as member functions, if needed.
V3Depth::depthAll(v3Global.rootp());
if (dumpMore) V3Global::dumpGlobalTree("depth.tree");
V3Global::dumpCheckGlobalTree("depth.tree", 0, dumpMore);
// Branch prediction
V3Branch::branchAll(v3Global.rootp());
@@ -570,7 +570,7 @@ void process () {
// Add C casts when longs need to become long-long and vice-versa
// Note depth may insert something needing a cast, so this must be last.
V3Cast::castAll(v3Global.rootp());
V3Global::dumpGlobalTree("cast.tree");
V3Global::dumpCheckGlobalTree("cast.tree");
}
V3Error::abortIfErrors();
@@ -676,7 +676,7 @@ int main(int argc, char** argv, char** env) {
}
// Final steps
V3Global::dumpGlobalTree("final.tree",990);
V3Global::dumpCheckGlobalTree("final.tree",990);
V3Error::abortIfWarnings();
if (!v3Global.opt.lintOnly() && !v3Global.opt.cdc()
+2 -2
View File
@@ -713,7 +713,7 @@ sub execute {
@{$param{all_run_flags}},
);
if ($param{iv_pli}) {
unshift @cmd, "vvp -m $self->{obj_dir}/libvpi.so";
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},
@@ -1212,7 +1212,7 @@ sub _make_top_v {
print $fh " initial begin\n";
print $fh " \$display(\"-Tracing Waves to Dumpfile: $self->{vcd_filename}\");\n";
print $fh " \$dumpfile(\"$self->{vcd_filename}\");\n";
print $fh " \$dumpvars(12, t);\n";
print $fh " \$dumpvars(0, top);\n";
print $fh " end\n";
print $fh "`endif\n";
+78
View File
@@ -0,0 +1,78 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2013-2013 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License.
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "vpi_user.h"
class TestSimulator {
private:
struct SimTypes {
int verilator;
int icarus;
int mti;
int ncsim;
int vcs;
};
s_vpi_vlog_info m_info;
SimTypes m_simulators;
public:
TestSimulator() {
vpi_get_vlog_info(&m_info);
if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.verilator = true;
} else if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.icarus = true;
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
m_simulators.vcs = true;
} else {
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
__FILE__, __LINE__, m_info.product);
}
}
~TestSimulator() { }
// METHORS
private:
static TestSimulator& singleton() {
static TestSimulator s_singleton;
return s_singleton;
}
static const SimTypes& simulators() { return singleton().m_simulators; }
public:
static const s_vpi_vlog_info& get_info() { return singleton().m_info; }
// Simulator names
static bool is_icarus() { return simulators().icarus; }
static bool is_verilator() { return simulators().verilator; }
static bool is_mti() { return simulators().mti; }
static bool is_ncsim() { return simulators().ncsim; }
static bool is_vcs() { return simulators().vcs; }
// Simulator properties
static bool is_event_driven() { return !simulators().verilator; }
static bool has_get_scalar() { return !simulators().icarus; }
// return test level scope
static const char* top() {
if (simulators().verilator) {
return "t";
} else {
return "top.t";
}
}
// return absolute scope of obj
static const char* rooted(const char *obj) {
static char buf[256];
snprintf(buf, sizeof(buf), "%s.%s", top(), obj);
return buf;
}
};
#define VPI_HANDLE(signal) vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(signal), NULL);
+34
View File
@@ -0,0 +1,34 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2013-2013 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License.
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "vpi_user.h"
//======================================================================
class TestVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
bool m_free;
public:
TestVpiHandle() : m_handle(NULL), m_free(true) { }
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
operator vpiHandle () const { return m_handle; }
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
TestVpiHandle& nofree() {
m_free = false;
return *this;
}
};
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2=>["-no-order-clock-delay"],
);
execute (
check_finished => 1
);
ok(1);
1;
+131
View File
@@ -0,0 +1,131 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005 by Wilson Snyder.
module t (clk);
input clk;
reg [0:0] d1;
reg [2:0] d3;
reg [7:0] d8;
wire [0:0] q1;
wire [2:0] q3;
wire [7:0] q8;
// verilator lint_off UNOPTFLAT
reg ena;
// verilator lint_on UNOPTFLAT
condff #(12) condff
(.clk(clk), .sen(1'b0), .ena(ena),
.d({d8,d3,d1}),
.q({q8,q3,q1}));
integer cyc; initial cyc=1;
always @ (posedge clk) begin
if (cyc!=0) begin
//$write("%x %x %x %x\n", cyc, q8, q3, q1);
cyc <= cyc + 1;
if (cyc==1) begin
d1 <= 1'b1; d3<=3'h1; d8<=8'h11;
ena <= 1'b1;
end
if (cyc==2) begin
d1 <= 1'b0; d3<=3'h2; d8<=8'h33;
ena <= 1'b0;
end
if (cyc==3) begin
d1 <= 1'b1; d3<=3'h3; d8<=8'h44;
ena <= 1'b1;
// PROPER ANSWER is 8'h11, but we are negative-testing
//if (q8 != 8'h11) $stop;
if (q8 != 8'h33) $stop;
end
if (cyc==4) begin
d1 <= 1'b1; d3<=3'h4; d8<=8'h77;
ena <= 1'b1;
// PROPER ANSWER is 8'h11, but we are negative-testing
//if (q8 != 8'h11) $stop;
if (q8 != 8'h33) $stop;
end
if (cyc==5) begin
d1 <= 1'b1; d3<=3'h0; d8<=8'h88;
ena <= 1'b1;
// PROPER ANSWER is 8'h44, but we are negative-testing
//if (q8 != 8'h44) $stop;
end
if (cyc==6) begin
// PROPER ANSWER is 8'h77, but we are negative-testing
//if (q8 != 8'h77) $stop;
end
if (cyc==7) begin
// PROPER ANSWER is 8'h88, but we are negative-testing
//if (q8 != 8'h88) $stop;
end
//
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
end
endmodule
module condff (clk, sen, ena, d, q);
parameter WIDTH = 1;
input clk;
input sen;
input ena;
input [WIDTH-1:0] d;
output [WIDTH-1:0] q;
condffimp #(.WIDTH(WIDTH))
imp (.clk(clk), .sen(sen), .ena(ena), .d(d), .q(q));
endmodule
module condffimp (clk, sen, ena, d, q);
parameter WIDTH = 1;
input clk;
input sen;
input ena;
input [WIDTH-1:0] d;
output reg [WIDTH-1:0] q;
wire gatedclk;
clockgate clockgate (.clk(clk), .sen(sen), .ena(ena), .gatedclk(gatedclk));
always @(posedge gatedclk) begin
if (gatedclk === 1'bX) begin
q <= {WIDTH{1'bX}};
end
else begin
q <= d;
end
end
endmodule
module clockgate (clk, sen, ena, gatedclk);
input clk;
input sen;
input ena;
output gatedclk;
reg ena_b;
wire gatedclk = clk & ena_b;
// verilator lint_off COMBDLY
always @(clk or ena or sen) begin
if (~clk) begin
ena_b <= ena | sen;
end
else begin
if ((clk^sen)===1'bX) ena_b <= 1'bX;
end
end
// verilator lint_on COMBDLY
endmodule
+18 -1
View File
@@ -10,7 +10,21 @@ module t (/*AUTOARG*/
input clk;
reg toggle; initial toggle=0;
typedef struct packed {
union packed {
logic ua;
logic ub;
} u;
logic b;
} str_t;
reg toggle; initial toggle='0;
str_t stoggle; initial stoggle='0;
const reg aconst = '0;
reg [1:0][1:0] ptoggle; initial ptoggle=0;
integer cyc; initial cyc=1;
wire [7:0] cyc_copy = cyc[7:0];
@@ -51,6 +65,9 @@ module t (/*AUTOARG*/
cyc <= cyc + 1;
memory[cyc + 'd100] <= memory[cyc + 'd100] + 2'b1;
toggle <= '0;
stoggle.u <= toggle;
stoggle.b <= toggle;
ptoggle[0][0] <= toggle;
if (cyc==3) begin
toggle <= '1;
end
+1
View File
@@ -14,6 +14,7 @@
//*************************************************************************
#include <cstdio>
#include <cstring>
#include "svdpi.h"
//======================================================================
+11
View File
@@ -34,6 +34,9 @@ module t (/*AUTOARG*/);
var logic [ONES:0] sized_based_on_enum;
var enum logic [3:0] { QINVALID='1, QSEND={2'b0,2'h0}, QOP={2'b0,2'h1}, QCL={2'b0,2'h2},
QPR={2'b0,2'h3 }, QACK, QRSP } inv;
initial begin
if (e0 !== 0) $stop;
if (e1 !== 1) $stop;
@@ -61,6 +64,14 @@ module t (/*AUTOARG*/);
if (FIVE[BIT1] != 1'b0) $stop;
if (FIVE[BIT2] != 1'b1) $stop;
if (QINVALID != 15) $stop;
if (QSEND != 0) $stop;
if (QOP != 1) $stop;
if (QCL != 2) $stop;
if (QPR != 3) $stop;
if (QACK != 4) $stop;
if (QRSP != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+36
View File
@@ -0,0 +1,36 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
module t (/*AUTOARG*/);
function integer max2;
input integer x;
input integer y;
begin
begin : blk
automatic int temp;
temp = x;
end
end
max2 = ( x > y ) ? x : y;
endfunction
function integer max4;
input integer x;
input integer y;
input integer z;
input integer w;
// MAX2 is used multiple times
max4 = max2( max2( x, y ), max2( z, w ) );
endfunction
localparam MAX4 = max4( 1, 1, 0, 0 );
initial begin
if (MAX4 != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+3
View File
@@ -9,6 +9,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
v_flags2 => ["--lint-only"],
make_top_shell => 0,
make_main => 0,
verilator_make_gcc => 0,
);
ok(1);
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+26
View File
@@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module x;
// verilator lint_off UNPACKED
typedef struct {
int a;
} notpacked_t;
// verilator lint_on UNPACKED
typedef struct packed {
notpacked_t b;
} ispacked_t;
ispacked_t p;
initial begin
p.b = 1;
if (p.b != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+2 -1
View File
@@ -10,7 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
fails=>$Self->{v3},
expect=>
q{%Error: t/t_struct_unpacked_bad.v:8: Unsupported: Unpacked struct/union
q{%Warning-UNPACKED: t/t_struct_unpacked_bad.v:\d+: Unsupported: Unpacked struct/union
%Warning-UNPACKED: Use .*
.*%Error: Exiting due to.*},
);
+9 -1
View File
@@ -10,7 +10,15 @@ module x;
} notpacked_t;
typedef struct packed {
notpacked_t a;
notpacked_t b;
} ispacked_t;
ispacked_t p;
initial begin
p.b = 1;
if (p.b != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+5
View File
@@ -12,8 +12,13 @@ module t (/*AUTOARG*/
const logic [2:0] five = 3'd5;
const logic unsigned [31:0] var_const = 22;
logic [7:0] res_const;
assign res_const = var_const[7:0]; // bug693
always @ (posedge clk) begin
if (five !== 3'd5) $stop;
if (res_const !== 8'd22) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+283
View File
@@ -0,0 +1,283 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License.
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifdef IS_VPI
#include "vpi_user.h"
#include <cstdlib>
#else
#include "Vt_vpi_get.h"
#include "verilated.h"
#include "svdpi.h"
#include "Vt_vpi_get__Dpi.h"
#include "verilated_vpi.h"
#include "verilated_vpi.cpp"
#include "verilated_vcd_c.h"
#endif
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_get.cpp"
#define TEST_MSG if (0) printf
unsigned int main_time = false;
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
FILENM,__LINE__, (got), (exp)); \
return __LINE__; \
}
#define CHECK_RESULT_NZ(got) \
if (!(got)) { \
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM,__LINE__); \
return __LINE__; \
}
// Use cout to avoid issues with %d/%lx etc
#define CHECK_RESULT(got, exp) \
if ((got) != (exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__ \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_HEX(got, exp) \
if ((got) != (exp)) { \
cout<<dec<<"%Error: "<<FILENM<<":"<<__LINE__<<hex \
<<": GOT = "<<(got)<<" EXP = "<<(exp)<<endl; \
return __LINE__; \
}
#define CHECK_RESULT_CSTR(got, exp) \
if (strcmp((got),(exp))) { \
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", \
FILENM,__LINE__, (got)?(got):"<null>", (exp)?(exp):"<null>"); \
return __LINE__; \
}
#define CHECK_RESULT_CSTR_STRIP(got, exp) \
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int scalar, int type) {
s_vpi_value value = {
vpiIntVal
};
// check size of object
int vpisize = vpi_get(vpiSize, handle);
CHECK_RESULT(vpisize, size);
// icarus verilog does not support vpiScalar, vpiVector or vpi*Range
if (TestSimulator::has_get_scalar()) {
int vpiscalar = vpi_get(vpiScalar, handle);
CHECK_RESULT((bool)vpiscalar, (bool)scalar);
int vpivector = vpi_get(vpiVector, handle);
CHECK_RESULT((bool)vpivector, (bool)!scalar);
}
// Icarus only supports ranges on memories
if (!scalar && !(TestSimulator::is_icarus() && type != vpiMemory)) {
TestVpiHandle left_h, right_h;
// check coherency for vectors
// get left hand side of range
left_h = vpi_handle(vpiLeftRange, handle);
CHECK_RESULT_NZ(left_h);
vpi_get_value(left_h, &value);
int coherency = value.value.integer;
// get right hand side of range
right_h = vpi_handle(vpiRightRange, handle);
CHECK_RESULT_NZ(right_h);
vpi_get_value(right_h, &value);
TEST_MSG("%d:%d\n", coherency, value.value.integer);
coherency -= value.value.integer;
// calculate size & check
coherency = abs(coherency) + 1;
CHECK_RESULT(coherency, size);
}
// Only check direction on ports
if (type == vpiPort) {
// check direction of object
int vpidir = vpi_get(vpiDirection, handle);
// Don't check port directions in verilator
// see #681
if (!TestSimulator::is_verilator()) {
CHECK_RESULT(vpidir, direction);
}
}
// check type of object
int vpitype = vpi_get(vpiType, handle);
if (!(TestSimulator::is_verilator() && type == vpiPort)) {
// Don't check for ports in verilator
// see #681
CHECK_RESULT(vpitype, type);
}
return 0; // Ok
}
struct params {
const char* signal;
struct {
unsigned int size;
unsigned int direction;
unsigned int scalar;
unsigned int type;
} attributes, children;
} values[] = {
{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}},
{"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
{"onetwo", {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory}, {0, 0, 0, 0}},
{"fourthreetwoone", {2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiMemoryWord}},
{"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
{"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}},
{"testout", {24, vpiOutput, 0, vpiPort}, {0, 0, 0, 0}},
{"sub.subin", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
{"sub.subout", {1, vpiOutput, 1, vpiPort}, {0, 0, 0, 0}},
{NULL, {0, 0, 0, 0}, {0, 0, 0, 0}}
};
int mon_check_props() {
struct params* value = values;
while (value->signal) {
TestVpiHandle h = VPI_HANDLE(value->signal);
CHECK_RESULT_NZ(h);
TEST_MSG("%s\n", value->signal);
if (int status = _mon_check_props(h, value->attributes.size, value->attributes.direction, value->attributes.scalar, value->attributes.type)) return status;
if (value->children.size) {
int size = 0;
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, h);
while (TestVpiHandle word_h = vpi_scan(iter_h.nofree())) {
// check size and range
if (int status = _mon_check_props(word_h, value->children.size, value->children.direction, value->children.scalar, value->children.type)) return status;
size++;
}
CHECK_RESULT(size, value->attributes.size);
}
value++;
}
return 0;
}
int mon_check() {
// Callback from initial block in monitor
if (int status = mon_check_props()) return status;
return 0; // Ok
}
//======================================================================
#ifdef IS_VPI
static int mon_check_vpi() {
vpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {
vpi_compat_bootstrap,
0
};
#else
double sc_time_stamp () {
return main_time;
}
int main(int argc, char **argv, char **env) {
double sim_time = 1100;
Verilated::commandArgs(argc, argv);
Verilated::debug(0);
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
#ifdef VERILATOR
# ifdef TEST_VERBOSE
Verilated::scopesDump();
# endif
#endif
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
#if VM_TRACE
VL_PRINTF("Enabling waves...\n");
topp->trace (tfp, 99);
tfp->open ("obj_dir/t_vpi_var/simx.vcd");
#endif
topp->eval();
topp->clk = 0;
main_time += 10;
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += 1;
topp->eval();
VerilatedVpi::callValueCbs();
topp->clk = !topp->clk;
//mon_do();
#if VM_TRACE
if (tfp) tfp->dump (main_time);
#endif
}
if (!Verilated::gotFinish()) {
vl_fatal(FILENM,__LINE__,"main", "%Error: Timeout; never got a $finish");
}
topp->final();
#if VM_TRACE
if (tfp) tfp->close();
#endif
delete topp; topp=NULL;
exit(0L);
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2010 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_get.cpp"],
make_pli => 1,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2 => ["+define+USE_VPI_NOT_DPI"],
);
execute (
iv_pli => 1,
check_finished=>1
);
ok(1);
1;
+71
View File
@@ -0,0 +1,71 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2010 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
`ifdef USE_VPI_NOT_DPI
//We call it via $c so we can verify DPI isn't required - see bug572
`else
import "DPI-C" context function integer mon_check();
`endif
module t (/*AUTOARG*/
// Inputs
input clk /*verilator public_flat_rd */,
// test ports
input [15:0] testin /*verilator public_flat_rd */,
output [23:0] testout /*verilator public_flat_rw @(posedge clk) */
);
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
reg onebit /*verilator public_flat_rw @(posedge clk) */;
reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */;
reg onetwo [1:2] /*verilator public_flat_rw @(posedge clk) */;
reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */;
integer status;
`ifdef iverilog
// stop icarus optimizing signals away
wire redundant = onebit | onetwo[1] | twoone | fourthreetwoone[3];
`endif
wire subin /*verilator public_flat_rd*/;
wire subout /*verilator public_flat_rd*/;
sub sub(.*);
// Test loop
initial begin
`ifdef VERILATOR
status = $c32("mon_check()");
`endif
`ifdef iverilog
status = $mon_check();
`endif
`ifndef USE_VPI_NOT_DPI
status = mon_check();
`endif
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule : t
module sub (
input subin /*verilator public_flat_rd*/,
output subout /*verilator public_flat_rd*/
);
endmodule : sub
+29 -40
View File
@@ -16,6 +16,7 @@
#ifdef IS_VPI
#include "vpi_user.h"
#include <cstdlib>
#else
@@ -36,6 +37,9 @@
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_memory.cpp"
@@ -45,19 +49,6 @@ unsigned int main_time = 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_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
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", \
@@ -96,30 +87,14 @@ public:
#define CHECK_RESULT_CSTR_STRIP(got, exp) \
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
// ideally we should be able to iterate on vpiRange against a list of this struct
typedef struct range {
int size;
int left;
int right;
} range_s, *range_p;
int _mon_check_range(VlVpiHandle& handle, int size, int left, int right) {
VlVpiHandle iter_h, rng_h, left_h, right_h;
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);
/*
// get range and check against expected
iter_h = vpi_iterate(vpiRange, handle);
CHECK_RESULT_NZ(iter_h);
rng_h = vpi_scan(iter_h);
CHECK_RESULT_NZ(rng_h);
int vpitype = vpi_get(vpiType, rng_h);
CHECK_RESULT(vpitype, vpiRange);
*/
// check size of range
vpisize = vpi_get(vpiSize, handle);
CHECK_RESULT(vpisize, size);
@@ -128,28 +103,33 @@ int _mon_check_range(VlVpiHandle& handle, int size, int left, int right) {
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;
VlVpiHandle mem_h, lcl_h;
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*)"t.mem0", NULL);
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);
_mon_check_range(mem_h, 16, 16, 1);
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;
@@ -157,7 +137,7 @@ int _mon_check_memory() {
value.value.integer = ++cnt;
vpi_put_value(lcl_h, &value, NULL, vpiNoDelay);
// check size and range
_mon_check_range(lcl_h, 32, 31, 0);
if (int status = _mon_check_range(lcl_h, 32, 31, 0)) return status;
}
CHECK_RESULT(cnt, 16); // should be 16 addresses
// iterate and accumulate
@@ -171,10 +151,8 @@ int _mon_check_memory() {
CHECK_RESULT(cnt, 16); // should be 16 addresses
// don't care for non verilator
// (crashes on Icarus)
s_vpi_vlog_info info;
vpi_get_vlog_info(&info);
if (strcmp(info.product, "Verilator") != 0) {
vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", info.product);
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
@@ -202,9 +180,19 @@ int mon_check() {
#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, vpiSysFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check, 0, 0, 0},
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
@@ -222,6 +210,7 @@ void (*vlog_startup_routines[])() = {
};
#else
double sc_time_stamp () {
return main_time;
}
+1 -1
View File
@@ -11,7 +11,7 @@ compile (
make_top_shell => 0,
make_main => 0,
make_pli => 1,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -s t -o obj_dir/iv_t_vpi_memory/simiv"],
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"],
);
+12 -1
View File
@@ -38,8 +38,19 @@ extern "C" int mon_check();
`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) $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], 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
+3 -15
View File
@@ -25,6 +25,8 @@
#include <iostream>
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_unimpl.cpp"
@@ -35,20 +37,6 @@ unsigned int callback_count = false;
//======================================================================
class VlVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
public:
VlVpiHandle() : m_handle(NULL) { }
VlVpiHandle(vpiHandle h) : m_handle(h) { }
~VlVpiHandle() { if (m_handle) { vpi_release_handle(m_handle); m_handle=NULL; } }
operator vpiHandle () const { return m_handle; }
inline VlVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
};
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
@@ -88,7 +76,7 @@ public:
CHECK_RESULT_CSTR(got+strspn(got, " "), exp)
int _mon_check_unimpl(p_cb_data cb_data) {
static VlVpiHandle cb, clk_h;
static TestVpiHandle cb, clk_h;
if (cb_data) {
// this is the callback
s_vpi_error_info info;
+124 -64
View File
@@ -13,6 +13,12 @@
//
//*************************************************************************
#ifdef IS_VPI
#include "vpi_user.h"
#else
#include "Vt_vpi_var.h"
#include "verilated.h"
#include "svdpi.h"
@@ -23,7 +29,16 @@
#include "verilated_vpi.cpp"
#include "verilated_vcd_c.h"
#endif
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_var.cpp"
@@ -39,20 +54,6 @@ unsigned int callback_count_strs_max = 500;
//======================================================================
class VlVpiHandle {
/// For testing, etc, wrap vpiHandle in an auto-releasing class
vpiHandle m_handle;
public:
VlVpiHandle() : m_handle(NULL) { }
VlVpiHandle(vpiHandle h) : m_handle(h) { }
~VlVpiHandle() { if (m_handle) { vpi_release_handle(m_handle); m_handle=NULL; } }
operator vpiHandle () const { return m_handle; }
inline VlVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
};
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", \
@@ -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,55 +232,57 @@ 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,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,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,2);
VlVpiHandle vh13 = vpi_handle(vpiRightRange, vh11);
TestVpiHandle vh13 = vpi_handle(vpiRightRange, vh11);
CHECK_RESULT_NZ(vh13);
vpi_get_value(vh13, &tmpValue);
CHECK_RESULT(tmpValue.value.integer,1);
@@ -276,30 +294,30 @@ int _mon_check_var() {
int _mon_check_varlist() {
const char* p;
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.sub", NULL);
TestVpiHandle vh2 = VPI_HANDLE("sub");
CHECK_RESULT_NZ(vh2);
VlVpiHandle vh10 = vpi_iterate(vpiReg, vh2);
CHECK_RESULT_NZ(vh10);
TestVpiHandle vh10 = vpi_iterate(vpiReg, vh2);
CHECK_RESULT_NZ(vh10.nofree());
VlVpiHandle vh11 = vpi_scan(vh10);
TestVpiHandle vh11 = vpi_scan(vh10);
CHECK_RESULT_NZ(vh11);
p = vpi_get_str(vpiFullName, vh11);
CHECK_RESULT_CSTR(p, "t.sub.subsig1");
CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig1"));
VlVpiHandle vh12 = vpi_scan(vh10);
TestVpiHandle vh12 = vpi_scan(vh10);
CHECK_RESULT_NZ(vh12);
p = vpi_get_str(vpiFullName, vh12);
CHECK_RESULT_CSTR(p, "t.sub.subsig2");
CHECK_RESULT_CSTR(p, TestSimulator::rooted("sub.subsig2"));
VlVpiHandle vh13 = vpi_scan(vh10);
TestVpiHandle vh13 = vpi_scan(vh10);
CHECK_RESULT(vh13,0);
return 0;
}
int _mon_check_getput() {
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.onebit", NULL);
TestVpiHandle vh2 = VPI_HANDLE("onebit");
CHECK_RESULT_NZ(vh2);
s_vpi_value v;
@@ -321,7 +339,7 @@ int _mon_check_getput() {
}
int _mon_check_quad() {
VlVpiHandle vh2 = vpi_handle_by_name((PLI_BYTE8*)"t.quads", NULL);
TestVpiHandle vh2 = VPI_HANDLE("quads");
CHECK_RESULT_NZ(vh2);
s_vpi_value v;
@@ -332,9 +350,9 @@ int _mon_check_quad() {
t.high = 0;
t.low = 0;
VlVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2);
TestVpiHandle vhidx2 = vpi_handle_by_index(vh2, 2);
CHECK_RESULT_NZ(vhidx2);
VlVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3);
TestVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3);
CHECK_RESULT_NZ(vhidx2);
v.format = vpiVectorVal;
@@ -366,15 +384,15 @@ int _mon_check_string() {
const char *initial;
const char *value;
} text_test_obs[] = {
{"t.text_byte", "B", "xxA"}, // x's dropped
{"t.text_half", "Hf", "xxT2"}, // x's dropped
{"t.text_word", "Word", "Tree"},
{"t.text_long", "Long64b", "44Four44"},
{"t.text" , "Verilog Test module", "lorem ipsum"},
{"text_byte", "B", "xxA"}, // x's dropped
{"text_half", "Hf", "xxT2"}, // x's dropped
{"text_word", "Word", "Tree"},
{"text_long", "Long64b", "44Four44"},
{"text" , "Verilog Test module", "lorem ipsum"},
};
for (int i=0; i<5; i++) {
VlVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)text_test_obs[i].name, NULL);
TestVpiHandle vh1 = VPI_HANDLE(text_test_obs[i].name);
CHECK_RESULT_NZ(vh1);
s_vpi_value v;
@@ -397,9 +415,9 @@ int _mon_check_string() {
}
int _mon_check_putget_str(p_cb_data cb_data) {
static VlVpiHandle cb;
static TestVpiHandle cb;
static struct {
VlVpiHandle scope, sig, rfr, check, verbose;
TestVpiHandle scope, sig, rfr, check, verbose;
char str[128+1]; // char per bit plus null terminator
int type; // value type in .str
union {
@@ -492,7 +510,7 @@ int _mon_check_putget_str(p_cb_data cb_data) {
// setup and install
for (int i=1; i<=128; i++) {
char buf[32];
snprintf(buf, sizeof(buf), "t.arr[%d].arr", i);
snprintf(buf, sizeof(buf), TestSimulator::rooted("arr[%d].arr"), i);
CHECK_RESULT_NZ(data[i].scope = vpi_handle_by_name((PLI_BYTE8*)buf, NULL));
CHECK_RESULT_NZ(data[i].sig = vpi_handle_by_name((PLI_BYTE8*)"sig", data[i].scope));
CHECK_RESULT_NZ(data[i].rfr = vpi_handle_by_name((PLI_BYTE8*)"rfr", data[i].scope));
@@ -502,12 +520,13 @@ int _mon_check_putget_str(p_cb_data cb_data) {
static t_cb_data cb_data;
static s_vpi_value v;
static VlVpiHandle count_h = vpi_handle_by_name((PLI_BYTE8*)"t.count", NULL);
static TestVpiHandle count_h = VPI_HANDLE("count");
cb_data.reason = cbValueChange;
cb_data.cb_rtn = _mon_check_putget_str; // this function
cb_data.obj = count_h;
cb_data.value = &v;
cb_data.time = NULL;
v.format = vpiIntVal;
cb = vpi_register_cb(&cb_data);
@@ -524,12 +543,15 @@ int _mon_check_vlog_info() {
CHECK_RESULT_CSTR(vlog_info.argv[1], "+PLUS");
CHECK_RESULT_CSTR(vlog_info.argv[2], "+INT=1234");
CHECK_RESULT_CSTR(vlog_info.argv[3], "+STRSTR");
CHECK_RESULT_CSTR(vlog_info.product, "Verilator");
CHECK_RESULT(strlen(vlog_info.version) > 0, 1);
if (TestSimulator::is_verilator()) {
CHECK_RESULT_CSTR(vlog_info.product, "Verilator");
CHECK_RESULT(strlen(vlog_info.version) > 0, 1);
}
return 0;
}
#ifndef IS_VPI
#define CHECK_ENUM_STR(fn, enum) \
do { \
const char* strVal = VerilatedVpiError::fn(enum); \
@@ -567,6 +589,8 @@ int _mon_check_vl_str() {
return 0;
}
#endif
int mon_check() {
// Callback from initial block in monitor
if (int status = _mon_check_mcd()) return status;
@@ -579,12 +603,46 @@ int mon_check() {
if (int status = _mon_check_string()) return status;
if (int status = _mon_check_putget_str(NULL)) return status;
if (int status = _mon_check_vlog_info()) return status;
#ifndef IS_VPI
if (int status = _mon_check_vl_str()) return status;
#endif
return 0; // Ok
}
//======================================================================
#ifdef IS_VPI
static int mon_check_vpi() {
vpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {
{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0
};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {
vpi_compat_bootstrap,
0
};
#else
double sc_time_stamp () {
return main_time;
@@ -640,3 +698,5 @@ int main(int argc, char **argv, char **env) {
delete topp; topp=NULL;
exit(0L);
}
#endif
+5
View File
@@ -10,10 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
make_top_shell => 0,
make_main => 0,
make_pli => 1,
sim_time => 2100,
iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES"],
v_flags2 => ["+define+USE_VPI_NOT_DPI"],
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --no-l2name $Self->{t_dir}/t_vpi_var.cpp"],
);
execute (
iv_pli => 1,
check_finished=>1,
all_run_flags => ['+PLUS +INT=1234 +STRSTR']
);
+22 -6
View File
@@ -5,7 +5,7 @@
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
`ifdef VERILATOR
`ifdef USE_VPI_NOT_DPI
//We call it via $c so we can verify DPI isn't required - see bug572
`else
import "DPI-C" context function integer mon_check();
@@ -45,7 +45,9 @@ extern "C" int mon_check();
// Test loop
initial begin
count = 0;
onebit = 1'b0;
fourthreetwoone[3] = 0; // stop icarus optimizing away
text_byte = "B";
text_half = "Hf";
text_word = "Word";
@@ -53,13 +55,18 @@ extern "C" int mon_check();
text = "Verilog Test module";
`ifdef VERILATOR
status = $c32("mon_check()");
`else
status = mon_check();
`endif
`ifdef iverilog
status = $mon_check();
`endif
`ifndef USE_VPI_NOT_DPI
status = mon_check();
`endif
if (status!=0) begin
$write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("%%Info: Checking results\n");
if (onebit != 1'b1) $stop;
if (quads[2] != 62'h12819213_abd31a1c) $stop;
if (quads[3] != 62'h1c77bb9b_3784ea09) $stop;
@@ -83,16 +90,20 @@ extern "C" int mon_check();
genvar i;
generate
for (i=1;i<=128;i++) begin : arr
for (i=1; i<=128; i=i+1) begin : arr
arr #(.LENGTH(i)) arr();
end endgenerate
endmodule
endmodule : t
module sub;
reg subsig1 /*verilator public_flat_rd*/;
reg subsig2 /*verilator public_flat_rd*/;
endmodule
`ifdef iverilog
// stop icarus optimizing signals away
wire redundant = subsig1 | subsig2;
`endif
endmodule : sub
module arr;
@@ -104,6 +115,11 @@ module arr;
reg check /*verilator public_flat_rw*/;
reg verbose /*verilator public_flat_rw*/;
initial begin
sig = {LENGTH{1'b0}};
rfr = {LENGTH{1'b0}};
end
always @(posedge check) begin
if (verbose) $display("%m : %x %x", sig, rfr);
if (check && sig != rfr) $stop;