Support vpiModule, bug1469.
Add very basic support for vpiModule. Basically it allows to traverse the module tree to find a variable etc. It does not support more than vpi_iterate and vpi_scan for vpiModule along basic operations like vpi_get_str on vpiModule. The support is added non-intrusively to non-VPI verilator runs. It essentially: - Tracks the creation of cell instances and keeps them alive until the emit phase. They are there converted to scopes if modules. - Emits empty (don't add anything during construction) VerilatedScopes for all inlined modules, only for those inlined modules that are on the hierarchical path to public variables. - Adds VerilatedHierarchy as abstraction to structure of the scopes. It is only created for VPI designs. It allows to traverse the hierarchy from the top (NULL). Signed-off-by: Stefan Wallentowitz <stefan@wallentowitz.de> Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
parent
66209d1114
commit
045ff25f80
2
Changes
2
Changes
|
|
@ -8,6 +8,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
*** Add --public-flat-rw, bug1511. [Stefan Wallentowitz]
|
*** Add --public-flat-rw, bug1511. [Stefan Wallentowitz]
|
||||||
|
|
||||||
|
*** Support vpiModule, bug1469. [Stefan Wallentowitz]
|
||||||
|
|
||||||
**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy]
|
**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy]
|
||||||
|
|
||||||
**** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader]
|
**** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader]
|
||||||
|
|
|
||||||
|
|
@ -2101,6 +2101,7 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
|
||||||
VerilatedScope::VerilatedScope() {
|
VerilatedScope::VerilatedScope() {
|
||||||
m_callbacksp = NULL;
|
m_callbacksp = NULL;
|
||||||
m_namep = NULL;
|
m_namep = NULL;
|
||||||
|
m_identifierp = NULL;
|
||||||
m_funcnumMax = 0;
|
m_funcnumMax = 0;
|
||||||
m_symsp = NULL;
|
m_symsp = NULL;
|
||||||
m_varsp = NULL;
|
m_varsp = NULL;
|
||||||
|
|
@ -2116,15 +2117,18 @@ VerilatedScope::~VerilatedScope() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp,
|
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp,
|
||||||
const char* suffixp) VL_MT_UNSAFE {
|
const char* suffixp, const char* identifier,
|
||||||
|
const Type type) VL_MT_UNSAFE {
|
||||||
// Slowpath - called once/scope at construction
|
// Slowpath - called once/scope at construction
|
||||||
// We don't want the space and reference-count access overhead of strings.
|
// We don't want the space and reference-count access overhead of strings.
|
||||||
m_symsp = symsp;
|
m_symsp = symsp;
|
||||||
|
m_type = type;
|
||||||
char* namep = new char[strlen(prefixp)+strlen(suffixp)+2];
|
char* namep = new char[strlen(prefixp)+strlen(suffixp)+2];
|
||||||
strcpy(namep, prefixp);
|
strcpy(namep, prefixp);
|
||||||
if (*prefixp && *suffixp) strcat(namep, ".");
|
if (*prefixp && *suffixp) strcat(namep, ".");
|
||||||
strcat(namep, suffixp);
|
strcat(namep, suffixp);
|
||||||
m_namep = namep;
|
m_namep = namep;
|
||||||
|
m_identifierp = identifier;
|
||||||
VerilatedImp::scopeInsert(this);
|
VerilatedImp::scopeInsert(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2229,6 +2233,10 @@ void VerilatedScope::scopeDump() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedHierarchy::add(VerilatedScope* fromp, VerilatedScope* top) {
|
||||||
|
VerilatedImp::hierarchyAdd(fromp, top);
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// VerilatedOneThreaded:: Methods
|
// VerilatedOneThreaded:: Methods
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,8 @@ public:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
/// Base class for all Verilated module classes
|
/// Base class for all Verilated module classes
|
||||||
|
|
||||||
|
class VerilatedScope;
|
||||||
|
|
||||||
class VerilatedModule {
|
class VerilatedModule {
|
||||||
VL_UNCOPYABLE(VerilatedModule);
|
VL_UNCOPYABLE(VerilatedModule);
|
||||||
private:
|
private:
|
||||||
|
|
@ -290,6 +292,11 @@ public: // But for internal use only
|
||||||
/// This class is initialized by main thread only. Reading post-init is thread safe.
|
/// This class is initialized by main thread only. Reading post-init is thread safe.
|
||||||
|
|
||||||
class VerilatedScope {
|
class VerilatedScope {
|
||||||
|
public:
|
||||||
|
typedef enum {
|
||||||
|
SCOPE_MODULE, SCOPE_OTHER
|
||||||
|
} Type; // Type of a scope, currently module is only interesting
|
||||||
|
private:
|
||||||
// Fastpath:
|
// Fastpath:
|
||||||
VerilatedSyms* m_symsp; ///< Symbol table
|
VerilatedSyms* m_symsp; ///< Symbol table
|
||||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||||
|
|
@ -297,16 +304,20 @@ class VerilatedScope {
|
||||||
// 4 bytes padding (on -m64), for rent.
|
// 4 bytes padding (on -m64), for rent.
|
||||||
VerilatedVarNameMap* m_varsp; ///< Variable map
|
VerilatedVarNameMap* m_varsp; ///< Variable map
|
||||||
const char* m_namep; ///< Scope name (Slowpath)
|
const char* m_namep; ///< Scope name (Slowpath)
|
||||||
|
const char* m_identifierp; ///< Identifier of scope (with escapes removed)
|
||||||
|
Type m_type; ///< Type of the scope
|
||||||
|
|
||||||
public: // But internals only - called from VerilatedModule's
|
public: // But internals only - called from VerilatedModule's
|
||||||
VerilatedScope();
|
VerilatedScope();
|
||||||
~VerilatedScope();
|
~VerilatedScope();
|
||||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) VL_MT_UNSAFE;
|
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffix,
|
||||||
|
const char* identifier, const Type type) VL_MT_UNSAFE;
|
||||||
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||||
void varInsert(int finalize, const char* namep, void* datap,
|
void varInsert(int finalize, const char* namep, void* datap,
|
||||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
|
const char* identifier() const { return m_identifierp; }
|
||||||
inline VerilatedSyms* symsp() const { return m_symsp; }
|
inline VerilatedSyms* symsp() const { return m_symsp; }
|
||||||
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
||||||
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
||||||
|
|
@ -322,6 +333,12 @@ public: // But internals only - called from VerilatedModule's
|
||||||
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
|
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Type type() { return m_type; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class VerilatedHierarchy {
|
||||||
|
public:
|
||||||
|
void add(VerilatedScope* fromp, VerilatedScope* top);
|
||||||
};
|
};
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef _VERILATED_IMP_H_
|
#ifndef _VERILATED_IMP_H_
|
||||||
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_)
|
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
|
||||||
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -187,6 +187,10 @@ class VerilatedImp {
|
||||||
|
|
||||||
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
||||||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
|
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
|
||||||
|
|
||||||
|
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
||||||
|
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy
|
||||||
|
|
||||||
// Slow - somewhat static:
|
// Slow - somewhat static:
|
||||||
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
||||||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
|
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
|
||||||
|
|
@ -321,6 +325,18 @@ public: // But only for verilated*.cpp
|
||||||
return &s_s.m_nameMap;
|
return &s_s.m_nameMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public: // But only for verilated*.cpp
|
||||||
|
// METHODS - hierarchy
|
||||||
|
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
||||||
|
// Slow ok - called at construction for VPI accessible elements
|
||||||
|
VerilatedLockGuard lock(s_s.m_hierMapMutex);
|
||||||
|
s_s.m_hierMap[fromp].push_back(top);
|
||||||
|
}
|
||||||
|
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
|
||||||
|
// Thread save only assuming this is called only after model construction completed
|
||||||
|
return &s_s.m_hierMap;
|
||||||
|
}
|
||||||
|
|
||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// METHODS - export names
|
// METHODS - export names
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "verilated_sym_props.h"
|
#include "verilated_sym_props.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
/// Types
|
/// Types
|
||||||
|
|
@ -63,4 +64,13 @@ public:
|
||||||
~VerilatedVarNameMap() {}
|
~VerilatedVarNameMap() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
|
||||||
|
|
||||||
|
class VerilatedHierarchyMap
|
||||||
|
: public std::map<const VerilatedScope*, VerilatedScopeVector> {
|
||||||
|
public:
|
||||||
|
VerilatedHierarchyMap() {}
|
||||||
|
~VerilatedHierarchyMap() {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,20 @@
|
||||||
/// Code available from: http://www.veripool.org/verilator
|
/// Code available from: http://www.veripool.org/verilator
|
||||||
///
|
///
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
#define _VERILATED_VPI_CPP_
|
||||||
|
|
||||||
#if VM_SC
|
#if VM_SC
|
||||||
# include "verilated_sc.h"
|
# include "verilated_sc.h"
|
||||||
#endif
|
#endif
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_vpi.h"
|
#include "verilated_vpi.h"
|
||||||
|
#include "verilated_imp.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Internal constants
|
// Internal constants
|
||||||
|
|
@ -307,6 +310,45 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VerilatedVpioModule : public VerilatedVpio {
|
||||||
|
const VerilatedScope* m_modulep;
|
||||||
|
const char* m_name;
|
||||||
|
const char* m_fullname;
|
||||||
|
public:
|
||||||
|
explicit VerilatedVpioModule(const VerilatedScope* modulep)
|
||||||
|
: m_modulep(modulep) {
|
||||||
|
m_fullname = m_modulep->name();
|
||||||
|
if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4;
|
||||||
|
m_name = m_modulep->identifier();
|
||||||
|
}
|
||||||
|
static inline VerilatedVpioModule* castp(vpiHandle h) {
|
||||||
|
return dynamic_cast<VerilatedVpioModule*>((VerilatedVpio*)h); }
|
||||||
|
virtual vluint32_t type() const { return vpiModule; }
|
||||||
|
const VerilatedScope* modulep() const { return m_modulep; }
|
||||||
|
virtual const char* name() const { return m_name; }
|
||||||
|
virtual const char* fullname() const { return m_fullname; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class VerilatedVpioModuleIter : public VerilatedVpio {
|
||||||
|
const std::vector<const VerilatedScope*> *m_vec;
|
||||||
|
std::vector<const VerilatedScope*>::const_iterator m_it;
|
||||||
|
public:
|
||||||
|
explicit VerilatedVpioModuleIter(const std::vector<const VerilatedScope*>& vec) : m_vec(&vec) {
|
||||||
|
m_it = m_vec->begin();
|
||||||
|
}
|
||||||
|
virtual ~VerilatedVpioModuleIter() {}
|
||||||
|
static inline VerilatedVpioModuleIter* castp(vpiHandle h) {
|
||||||
|
return dynamic_cast<VerilatedVpioModuleIter*>((VerilatedVpio*) h); }
|
||||||
|
virtual vluint32_t type() const { return vpiIterator; }
|
||||||
|
virtual vpiHandle dovpi_scan() {
|
||||||
|
if (m_it == m_vec->end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const VerilatedScope* modp = *m_it++;
|
||||||
|
return (new VerilatedVpioModule(modp))->castVpiHandle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
struct VerilatedVpiTimedCbsCmp {
|
struct VerilatedVpiTimedCbsCmp {
|
||||||
|
|
@ -999,7 +1041,7 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
if (VL_UNLIKELY(!namep)) return NULL;
|
if (VL_UNLIKELY(!namep)) return NULL;
|
||||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
|
||||||
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
|
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
|
||||||
const VerilatedVar* varp;
|
const VerilatedVar* varp = NULL;
|
||||||
const VerilatedScope* scopep;
|
const VerilatedScope* scopep;
|
||||||
std::string scopeAndName = namep;
|
std::string scopeAndName = namep;
|
||||||
if (voScopep) {
|
if (voScopep) {
|
||||||
|
|
@ -1019,9 +1061,19 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||||
baseNamep = dotp+1;
|
baseNamep = dotp+1;
|
||||||
scopename = std::string(namep, dotp-namep);
|
scopename = std::string(namep, dotp-namep);
|
||||||
}
|
}
|
||||||
scopep = Verilated::scopeFind(scopename.c_str());
|
|
||||||
if (!scopep) return NULL;
|
if (scopename.find(".") == std::string::npos) {
|
||||||
varp = scopep->varFind(baseNamep);
|
// This is a toplevel, hence search in our TOP ports first.
|
||||||
|
scopep = Verilated::scopeFind("TOP");
|
||||||
|
if (scopep) {
|
||||||
|
varp = scopep->varFind(baseNamep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!varp) {
|
||||||
|
scopep = Verilated::scopeFind(scopename.c_str());
|
||||||
|
if (!scopep) return NULL;
|
||||||
|
varp = scopep->varFind(baseNamep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!varp) return NULL;
|
if (!varp) return NULL;
|
||||||
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
|
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
|
||||||
|
|
@ -1133,6 +1185,14 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||||
return ((new VerilatedVpioVarIter(vop->scopep()))
|
return ((new VerilatedVpioVarIter(vop->scopep()))
|
||||||
->castVpiHandle());
|
->castVpiHandle());
|
||||||
}
|
}
|
||||||
|
case vpiModule: {
|
||||||
|
VerilatedVpioModule* vop = VerilatedVpioModule::castp(object);
|
||||||
|
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
|
||||||
|
const VerilatedScope *mod = vop ? vop->modulep() : NULL;
|
||||||
|
VerilatedHierarchyMap::const_iterator it = map->find((VerilatedScope*) mod);
|
||||||
|
if (it == map->end()) return 0;
|
||||||
|
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
||||||
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
|
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
|
||||||
|
|
|
||||||
|
|
@ -1879,21 +1879,27 @@ public:
|
||||||
|
|
||||||
class AstCellInline : public AstNode {
|
class AstCellInline : public AstNode {
|
||||||
// A instantiation cell that was removed by inlining
|
// A instantiation cell that was removed by inlining
|
||||||
// For communication between V3Inline and V3LinkDot only
|
// For communication between V3Inline and V3LinkDot,
|
||||||
|
// except for VPI runs where it exists until the end.
|
||||||
|
// It is augmented with the scope in V3Scope for VPI.
|
||||||
// Children: When 2 levels inlined, other CellInline under this
|
// Children: When 2 levels inlined, other CellInline under this
|
||||||
private:
|
private:
|
||||||
string m_name; // Cell name, possibly {a}__DOT__{b}...
|
string m_name; // Cell name, possibly {a}__DOT__{b}...
|
||||||
string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup
|
string m_origModName; // Original name of the module, ignoring name() changes, for dot lookup
|
||||||
|
AstScope* m_scopep; // The scope that the cell is inlined into
|
||||||
public:
|
public:
|
||||||
AstCellInline(FileLine* fl, const string& name, const string& origModName)
|
AstCellInline(FileLine* fl, const string& name, const string& origModName)
|
||||||
: AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origModName(origModName) {}
|
, m_name(name), m_origModName(origModName), m_scopep(NULL) {}
|
||||||
ASTNODE_NODE_FUNCS(CellInline)
|
ASTNODE_NODE_FUNCS(CellInline)
|
||||||
virtual void dump(std::ostream& str);
|
virtual void dump(std::ostream& str);
|
||||||
|
virtual const char* broken() const { BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; }
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
virtual string name() const { return m_name; } // * = Cell name
|
virtual string name() const { return m_name; } // * = Cell name
|
||||||
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
|
||||||
virtual void name(const string& name) { m_name = name; }
|
virtual void name(const string& name) { m_name = name; }
|
||||||
|
void scopep(AstScope* scp) { m_scopep = scp; }
|
||||||
|
AstScope* scopep() const { return m_scopep; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstCellRef : public AstNode {
|
class AstCellRef : public AstNode {
|
||||||
|
|
|
||||||
|
|
@ -853,6 +853,7 @@ public:
|
||||||
virtual void visit(AstTraceDecl*) {} // Handled outside the Visit class
|
virtual void visit(AstTraceDecl*) {} // Handled outside the Visit class
|
||||||
virtual void visit(AstTraceInc*) {} // Handled outside the Visit class
|
virtual void visit(AstTraceInc*) {} // Handled outside the Visit class
|
||||||
virtual void visit(AstCFile*) {} // Handled outside the Visit class
|
virtual void visit(AstCFile*) {} // Handled outside the Visit class
|
||||||
|
virtual void visit(AstCellInline*) {} // Handled outside the Visit class (EmitCSyms)
|
||||||
// Default
|
// Default
|
||||||
virtual void visit(AstNode* nodep) {
|
virtual void visit(AstNode* nodep) {
|
||||||
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
|
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
struct ScopeNameData { string m_symName; string m_prettyName;
|
struct ScopeData { string m_symName; string m_prettyName; string m_type;
|
||||||
ScopeNameData(const string& symName, const string& prettyName)
|
ScopeData(const string& symName, const string& prettyName, const string& type)
|
||||||
: m_symName(symName), m_prettyName(prettyName) {}
|
: m_symName(symName), m_prettyName(prettyName), m_type(type) {}
|
||||||
};
|
};
|
||||||
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
||||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||||
|
|
@ -60,9 +60,11 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
};
|
};
|
||||||
typedef std::map<string,ScopeFuncData> ScopeFuncs;
|
typedef std::map<string,ScopeFuncData> ScopeFuncs;
|
||||||
typedef std::map<string,ScopeVarData> ScopeVars;
|
typedef std::map<string,ScopeVarData> ScopeVars;
|
||||||
typedef std::map<string,ScopeNameData> ScopeNames;
|
typedef std::map<string,ScopeData> ScopeNames;
|
||||||
typedef std::pair<AstScope*,AstNodeModule*> ScopeModPair;
|
typedef std::pair<AstScope*,AstNodeModule*> ScopeModPair;
|
||||||
typedef std::pair<AstNodeModule*,AstVar*> ModVarPair;
|
typedef std::pair<AstNodeModule*,AstVar*> ModVarPair;
|
||||||
|
typedef std::vector<string> ScopeNameList;
|
||||||
|
typedef std::map<string, ScopeNameList> ScopeNameHierarchy;
|
||||||
struct CmpName {
|
struct CmpName {
|
||||||
inline bool operator() (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
inline bool operator() (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
||||||
return lhsp.first->name() < rhsp.first->name();
|
return lhsp.first->name() < rhsp.first->name();
|
||||||
|
|
@ -81,12 +83,14 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
// STATE
|
// STATE
|
||||||
AstCFunc* m_funcp; // Current function
|
AstCFunc* m_funcp; // Current function
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
std::vector<ScopeModPair> m_scopes; // Every scope by module
|
std::vector<ScopeModPair> m_scopes; // Every scope by module
|
||||||
std::vector<AstCFunc*> m_dpis; // DPI functions
|
std::vector<AstCFunc*> m_dpis; // DPI functions
|
||||||
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
ScopeNames m_scopeNames; // Each unique AstScopeName
|
||||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
|
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
|
||||||
ScopeVars m_scopeVars; // Each {scope,public-var}
|
ScopeVars m_scopeVars; // Each {scope,public-var}
|
||||||
|
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
||||||
|
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
|
||||||
V3LanguageWords m_words; // Reserved word detector
|
V3LanguageWords m_words; // Reserved word detector
|
||||||
int m_coverBins; // Coverage bin number
|
int m_coverBins; // Coverage bin number
|
||||||
int m_labelNum; // Next label number
|
int m_labelNum; // Next label number
|
||||||
|
|
@ -119,6 +123,57 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string scopeSymString(const string& scpname) {
|
||||||
|
string out = scpname;
|
||||||
|
string::size_type pos;
|
||||||
|
while ((pos = out.find("__PVT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "");
|
||||||
|
}
|
||||||
|
if (out.substr(0, 10) == "TOP__DOT__") out.replace(0, 10, "");
|
||||||
|
if (out.substr(0, 4) == "TOP.") out.replace(0, 4, "");
|
||||||
|
while ((pos = out.find('.')) != string::npos) {
|
||||||
|
out.replace(pos, 1, "__");
|
||||||
|
}
|
||||||
|
while ((pos = out.find("__DOT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "__");
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
string scopeDecodeIdentifier(const string& scpname) {
|
||||||
|
string out = scpname;
|
||||||
|
// Remove hierarchy
|
||||||
|
string::size_type pos = out.rfind(".");
|
||||||
|
if (pos != std::string::npos) out.erase(0, pos + 1);
|
||||||
|
// Decode all escaped characters
|
||||||
|
while ((pos = out.find("__0")) != string::npos) {
|
||||||
|
unsigned int x;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::hex << out.substr(pos+3, 2);
|
||||||
|
ss >> x;
|
||||||
|
out.replace(pos, 5, 1, (char) x);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void varHierarchyScopes(string scp) {
|
||||||
|
while (!scp.empty()) {
|
||||||
|
ScopeNames::const_iterator scpit = m_vpiScopeCandidates.find(scp);
|
||||||
|
if ((scpit != m_vpiScopeCandidates.end())
|
||||||
|
&& (m_scopeNames.find(scp) == m_scopeNames.end())) {
|
||||||
|
m_scopeNames.insert(make_pair(scpit->second.m_symName, scpit->second));
|
||||||
|
}
|
||||||
|
string::size_type pos = scp.rfind("__DOT__");
|
||||||
|
if (pos == string::npos) {
|
||||||
|
pos = scp.rfind(".");
|
||||||
|
if (pos == string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scp.resize(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void varsExpand() {
|
void varsExpand() {
|
||||||
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
|
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
|
||||||
// It would be less code if each module inserted its own variables.
|
// It would be less code if each module inserted its own variables.
|
||||||
|
|
@ -149,26 +204,14 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
|
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
|
||||||
string varBasePretty = AstNode::prettyName(varBase);
|
string varBasePretty = AstNode::prettyName(varBase);
|
||||||
string scpPretty = AstNode::prettyName(scpName);
|
string scpPretty = AstNode::prettyName(scpName);
|
||||||
string scpSym;
|
string scpSym = scopeSymString(scpName);
|
||||||
{
|
|
||||||
string out = scpName;
|
|
||||||
string::size_type pos;
|
|
||||||
while ((pos = out.find("__PVT__")) != string::npos) {
|
|
||||||
out.replace(pos, 7, "");
|
|
||||||
}
|
|
||||||
if (out.substr(0, 10) == "TOP__DOT__") out.replace(0, 10, "");
|
|
||||||
if (out.substr(0, 4) == "TOP.") out.replace(0, 4, "");
|
|
||||||
while ((pos = out.find('.')) != string::npos) {
|
|
||||||
out.replace(pos, 1, "__");
|
|
||||||
}
|
|
||||||
while ((pos = out.find("__DOT__")) != string::npos) {
|
|
||||||
out.replace(pos, 7, "__");
|
|
||||||
}
|
|
||||||
scpSym = out;
|
|
||||||
}
|
|
||||||
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
|
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
|
||||||
|
if (v3Global.opt.vpi()) {
|
||||||
|
varHierarchyScopes(scpName);
|
||||||
|
}
|
||||||
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
|
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
|
||||||
m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
|
m_scopeNames.insert(make_pair(scpSym, ScopeData(scpSym, scpPretty,
|
||||||
|
"SCOPE_OTHER")));
|
||||||
}
|
}
|
||||||
m_scopeVars.insert(
|
m_scopeVars.insert(
|
||||||
make_pair(scpSym + " " + varp->name(),
|
make_pair(scpSym + " " + varp->name(),
|
||||||
|
|
@ -178,12 +221,39 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void buildVpiHierarchy() {
|
||||||
|
for (ScopeNames::const_iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
|
if (it->second.m_type != "SCOPE_MODULE") continue;
|
||||||
|
|
||||||
|
string name = it->second.m_prettyName;
|
||||||
|
if (name.substr(0, 4) == "TOP.") name.replace(0, 4, "");
|
||||||
|
|
||||||
|
string above = name;
|
||||||
|
while (!above.empty()) {
|
||||||
|
string::size_type pos = above.rfind(".");
|
||||||
|
if (pos == string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
above.resize(pos);
|
||||||
|
if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) {
|
||||||
|
m_vpiScopeHierarchy[above].push_back(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_vpiScopeHierarchy[name] = std::vector<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNetlist* nodep) {
|
virtual void visit(AstNetlist* nodep) {
|
||||||
// Collect list of scopes
|
// Collect list of scopes
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
varsExpand();
|
varsExpand();
|
||||||
|
|
||||||
|
if (v3Global.opt.vpi()) {
|
||||||
|
buildVpiHierarchy();
|
||||||
|
}
|
||||||
|
|
||||||
// Sort by names, so line/process order matters less
|
// Sort by names, so line/process order matters less
|
||||||
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
||||||
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
|
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
|
||||||
|
|
@ -206,15 +276,33 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstCellInline* nodep) {
|
||||||
|
if (v3Global.opt.vpi()) {
|
||||||
|
string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER"
|
||||||
|
: "SCOPE_MODULE";
|
||||||
|
string name = nodep->scopep()->name() + "__DOT__" + nodep->name();
|
||||||
|
string name_dedot = AstNode::dedotName(name);
|
||||||
|
m_vpiScopeCandidates.insert(make_pair(name, ScopeData(scopeSymString(name),
|
||||||
|
name_dedot, type)));
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstScope* nodep) {
|
virtual void visit(AstScope* nodep) {
|
||||||
nameCheck(nodep);
|
nameCheck(nodep);
|
||||||
|
|
||||||
m_scopes.push_back(make_pair(nodep, m_modp));
|
m_scopes.push_back(make_pair(nodep, m_modp));
|
||||||
|
|
||||||
|
if (v3Global.opt.vpi() && !nodep->isTop()) {
|
||||||
|
m_vpiScopeCandidates.insert(make_pair(nodep->name(),
|
||||||
|
ScopeData(scopeSymString(nodep->name()),
|
||||||
|
nodep->name(), "SCOPE_MODULE")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstScopeName* nodep) {
|
virtual void visit(AstScopeName* nodep) {
|
||||||
string name = nodep->scopeSymName();
|
string name = nodep->scopeSymName();
|
||||||
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()<<" ss "<<name<<endl);
|
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()<<" ss "<<name<<endl);
|
||||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||||
m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettySymName())));
|
m_scopeNames.insert(make_pair(name, ScopeData(name, nodep->scopePrettySymName(),
|
||||||
|
"SCOPE_OTHER")));
|
||||||
}
|
}
|
||||||
if (nodep->dpiExport()) {
|
if (nodep->dpiExport()) {
|
||||||
UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function");
|
UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function");
|
||||||
|
|
@ -223,8 +311,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
} else {
|
} else {
|
||||||
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
|
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
|
||||||
m_scopeNames.insert(make_pair(nodep->scopeDpiName(),
|
m_scopeNames.insert(make_pair(nodep->scopeDpiName(),
|
||||||
ScopeNameData(nodep->scopeDpiName(),
|
ScopeData(nodep->scopeDpiName(),
|
||||||
nodep->scopePrettyDpiName())));
|
nodep->scopePrettyDpiName(),
|
||||||
|
"SCOPE_OTHER")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -353,17 +442,18 @@ void EmitCSyms::emitSymHdr() {
|
||||||
puts("uint32_t __Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
|
puts("uint32_t __Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Scope names
|
if (!m_scopeNames.empty()) { // Scope names
|
||||||
bool did = false;
|
puts("\n// SCOPE NAMES\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
if (!did) {
|
|
||||||
did = true;
|
|
||||||
puts("\n// SCOPE NAMES\n");
|
|
||||||
}
|
|
||||||
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v3Global.opt.vpi()) {
|
||||||
|
puts("\n// SCOPE HIERARCHY\n");
|
||||||
|
puts("VerilatedHierarchy __Vhier;\n");
|
||||||
|
}
|
||||||
|
|
||||||
puts("\n// CREATORS\n");
|
puts("\n// CREATORS\n");
|
||||||
puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n");
|
puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n");
|
||||||
puts(string("~")+symClassName()+"() {}\n");
|
puts(string("~")+symClassName()+"() {}\n");
|
||||||
|
|
@ -550,21 +640,49 @@ void EmitCSyms::emitSymImp() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Setup scope names
|
if (!m_scopeNames.empty()) { // Setup scope names
|
||||||
bool did = false;
|
puts("// Setup scopes\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
if (!did) {
|
|
||||||
did = true;
|
|
||||||
puts("// Setup scope names\n");
|
|
||||||
}
|
|
||||||
checkSplit(false);
|
checkSplit(false);
|
||||||
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
||||||
putsQuoted(it->second.m_prettyName);
|
putsQuoted(it->second.m_prettyName);
|
||||||
puts(");\n");
|
puts(", ");
|
||||||
|
putsQuoted(scopeDecodeIdentifier(it->second.m_prettyName));
|
||||||
|
puts(", VerilatedScope::"+it->second.m_type+");\n");
|
||||||
++m_numStmts;
|
++m_numStmts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v3Global.opt.vpi()) {
|
||||||
|
puts("\n// Setup scope hierarchy\n");
|
||||||
|
for (ScopeNames::const_iterator it = m_scopeNames.begin();
|
||||||
|
it != m_scopeNames.end(); ++it) {
|
||||||
|
string name = it->second.m_prettyName;
|
||||||
|
if (it->first == "TOP") continue;
|
||||||
|
name = name.replace(0, 4, ""); // Remove the "TOP."
|
||||||
|
if ((name.find(".") == string::npos) && (it->second.m_type == "SCOPE_MODULE")) {
|
||||||
|
puts("__Vhier.add(0, &__Vscope_" + it->second.m_symName + ");\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ScopeNameHierarchy::const_iterator it = m_vpiScopeHierarchy.begin();
|
||||||
|
it != m_vpiScopeHierarchy.end(); ++it) {
|
||||||
|
for (ScopeNameList::const_iterator lit = it->second.begin();
|
||||||
|
lit != it->second.end(); ++lit) {
|
||||||
|
string fromname = scopeSymString(it->first);
|
||||||
|
string toname = scopeSymString(*lit);
|
||||||
|
ScopeNames::const_iterator from = m_scopeNames.find(fromname);
|
||||||
|
ScopeNames::const_iterator to = m_scopeNames.find(toname);
|
||||||
|
UASSERT(from != m_scopeNames.end(), fromname+" not in m_scopeNames");
|
||||||
|
UASSERT(to != m_scopeNames.end(), toname+" not in m_scopeNames");
|
||||||
|
puts("__Vhier.add(");
|
||||||
|
puts("&__Vscope_"+from->second.m_symName+", ");
|
||||||
|
puts("&__Vscope_"+to->second.m_symName+");\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Everything past here is in the __Vfinal loop, so start a new split file if needed
|
// Everything past here is in the __Vfinal loop, so start a new split file if needed
|
||||||
closeSplit();
|
closeSplit();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1793,7 +1793,7 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstCellInline* nodep) {
|
virtual void visit(AstCellInline* nodep) {
|
||||||
checkNoDot(nodep);
|
checkNoDot(nodep);
|
||||||
if (m_statep->forScopeCreation()) {
|
if (m_statep->forScopeCreation() && !v3Global.opt.vpi()) {
|
||||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,9 @@ private:
|
||||||
|
|
||||||
// ***Note m_scopep is passed back to the caller of the routine (above)
|
// ***Note m_scopep is passed back to the caller of the routine (above)
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstCellInline* nodep) {
|
||||||
|
nodep->scopep(m_scopep);
|
||||||
|
}
|
||||||
virtual void visit(AstActive* nodep) {
|
virtual void visit(AstActive* nodep) {
|
||||||
nodep->v3fatalSrc("Actives now made after scoping");
|
nodep->v3fatalSrc("Actives now made after scoping");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
// -*- 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_module.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "svdpi.h"
|
||||||
|
|
||||||
|
#include "Vt_vpi_module__Dpi.h"
|
||||||
|
|
||||||
|
#include "verilated_vpi.h"
|
||||||
|
#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_module.cpp"
|
||||||
|
|
||||||
|
#define DEBUG if (0) printf
|
||||||
|
|
||||||
|
unsigned int main_time = false;
|
||||||
|
|
||||||
|
#define CHECK_RESULT_NZ(got) \
|
||||||
|
if (!(got)) { \
|
||||||
|
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM,__LINE__); \
|
||||||
|
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__; \
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int mon_check() {
|
||||||
|
vpiHandle it = vpi_iterate(vpiModule, NULL);
|
||||||
|
CHECK_RESULT_NZ(it);
|
||||||
|
|
||||||
|
vpiHandle topmod = vpi_scan(it);
|
||||||
|
CHECK_RESULT_NZ(topmod);
|
||||||
|
|
||||||
|
char* name = vpi_get_str(vpiName, topmod);
|
||||||
|
CHECK_RESULT_NZ(name);
|
||||||
|
CHECK_RESULT_CSTR(name, "t");
|
||||||
|
|
||||||
|
it = vpi_iterate(vpiModule, topmod);
|
||||||
|
CHECK_RESULT_NZ(it);
|
||||||
|
|
||||||
|
vpiHandle mod = vpi_scan(it);
|
||||||
|
CHECK_RESULT_NZ(mod);
|
||||||
|
|
||||||
|
name = vpi_get_str(vpiName, mod);
|
||||||
|
CHECK_RESULT_CSTR(name, "mod_a");
|
||||||
|
|
||||||
|
it = vpi_iterate(vpiModule, mod);
|
||||||
|
CHECK_RESULT_NZ(it);
|
||||||
|
|
||||||
|
mod = vpi_scan(it);
|
||||||
|
CHECK_RESULT_NZ(mod);
|
||||||
|
|
||||||
|
name = vpi_get_str(vpiName, mod);
|
||||||
|
if (strcmp(name, "mod_b") == 0) {
|
||||||
|
// Full visibility in other simulators, skip mod_b
|
||||||
|
mod = vpi_scan(it);
|
||||||
|
CHECK_RESULT_NZ(mod);
|
||||||
|
name = vpi_get_str(vpiName, mod);
|
||||||
|
}
|
||||||
|
CHECK_RESULT_CSTR(name, "mod_c.");
|
||||||
|
|
||||||
|
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);
|
||||||
|
// we're going to be checking for these errors do don't crash out
|
||||||
|
Verilated::fatalOnVpiError(0);
|
||||||
|
|
||||||
|
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
||||||
|
|
||||||
|
#ifdef VERILATOR
|
||||||
|
# ifdef TEST_VERBOSE
|
||||||
|
Verilated::scopesDump();
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if VM_TRACE
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
VL_PRINTF("Enabling waves...\n");
|
||||||
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
|
topp->trace(tfp, 99);
|
||||||
|
tfp->open(STRINGIFY(TEST_OBJ_DIR) "/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
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/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.
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
skip("Known compiler limitation")
|
||||||
|
if $Self->cxx_version =~ /\(GCC\) 4.4/;
|
||||||
|
|
||||||
|
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 --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
iv_pli => 1,
|
||||||
|
check_finished => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
integer status;
|
||||||
|
|
||||||
|
wire a, b, x;
|
||||||
|
|
||||||
|
A mod_a(/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.x (x),
|
||||||
|
// Inputs
|
||||||
|
.clk (clk),
|
||||||
|
.a (a),
|
||||||
|
.b (b));
|
||||||
|
|
||||||
|
// 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_module.cpp:%0d: C Test failed\n", status);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule : t
|
||||||
|
|
||||||
|
module A(/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
x,
|
||||||
|
// Inputs
|
||||||
|
clk, a, b
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
input a, b;
|
||||||
|
output x;
|
||||||
|
|
||||||
|
wire y, c;
|
||||||
|
|
||||||
|
B mod_b(/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.y (y),
|
||||||
|
// Inputs
|
||||||
|
.b (b),
|
||||||
|
.c (c));
|
||||||
|
|
||||||
|
C \mod_c. (/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.x (x),
|
||||||
|
// Inputs
|
||||||
|
.clk (clk),
|
||||||
|
.a (a),
|
||||||
|
.y (y));
|
||||||
|
|
||||||
|
endmodule : A
|
||||||
|
|
||||||
|
module B(/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
y,
|
||||||
|
// Inputs
|
||||||
|
b, c
|
||||||
|
); /*verilator public_module*/
|
||||||
|
input b, c;
|
||||||
|
|
||||||
|
output reg y;
|
||||||
|
|
||||||
|
always @(*) begin : myproc
|
||||||
|
y = b ^ c;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module C(/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
x,
|
||||||
|
// Inputs
|
||||||
|
clk, a, y
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
input a, y;
|
||||||
|
|
||||||
|
output reg x /* verilator public_flat_rw */;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
x <= a & y;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue