Support DPI context imports
This commit is contained in:
parent
2dc7b7ad78
commit
17bf13fcb6
|
|
@ -23,7 +23,8 @@
|
|||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilated.h"
|
||||
#define _VERILATED_CPP_
|
||||
#include "verilatedimp.h"
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -37,38 +38,11 @@ int Verilated::s_debug = 1;
|
|||
bool Verilated::s_calcUnusedSigs = false;
|
||||
bool Verilated::s_gotFinish = false;
|
||||
bool Verilated::s_assertOn = true;
|
||||
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
|
||||
VL_THREAD const char* Verilated::t_dpiFilename = "";
|
||||
VL_THREAD int Verilated::t_dpiLineno = 0;
|
||||
|
||||
//===========================================================================
|
||||
// Local Implementation Globals
|
||||
// (Not in Verilated as they can be slow, and we want to mimimize the STL imports)
|
||||
|
||||
class VerilatedImp {
|
||||
protected:
|
||||
friend class Verilated;
|
||||
typedef vector<string> ArgVec;
|
||||
static ArgVec s_argVec; // Argument list
|
||||
static bool s_argVecLoaded; // Ever loaded argument list
|
||||
// METHODS
|
||||
public: // But only for this C file
|
||||
static string argPlusMatch(const char* prefixp) {
|
||||
int len = strlen(prefixp);
|
||||
if (!s_argVecLoaded) {
|
||||
s_argVecLoaded = true; // Complain only once
|
||||
vl_fatal("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::iterator it=s_argVec.begin(); it!=s_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
VerilatedImp::ArgVec VerilatedImp::s_argVec;
|
||||
bool VerilatedImp::s_argVecLoaded = false;
|
||||
VerilatedImp VerilatedImp::s_s;
|
||||
|
||||
//===========================================================================
|
||||
// User definable functions
|
||||
|
|
@ -938,12 +912,7 @@ const char* Verilated::catName(const char* n1, const char* n2) {
|
|||
}
|
||||
|
||||
void Verilated::commandArgs(int argc, const char** argv) {
|
||||
VerilatedImp::s_argVec.clear();
|
||||
for (int i=0; i<argc; i++) {
|
||||
VerilatedImp::s_argVec.push_back(argv[i]);
|
||||
}
|
||||
// Can't just test later for empty vector, no arguments is ok
|
||||
VerilatedImp::s_argVecLoaded = true;
|
||||
VerilatedImp::commandArgs(argc,argv);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
@ -957,4 +926,22 @@ VerilatedModule::~VerilatedModule() {
|
|||
if (m_namep) free((void*)m_namep); m_namep=NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// VerilatedScope:: Methods
|
||||
|
||||
VerilatedScope::~VerilatedScope() {
|
||||
VerilatedImp::scopeErase(this);
|
||||
delete [] m_namep; m_namep = NULL;
|
||||
}
|
||||
|
||||
void VerilatedScope::configure(const char* prefixp, const char* suffixp) {
|
||||
// Slow ok - called once/scope at construction
|
||||
// We don't want the space and reference-count access overhead of strings.
|
||||
char* namep = new char[strlen(prefixp)+strlen(suffixp)+2];
|
||||
strcpy(namep, prefixp);
|
||||
strcat(namep, suffixp);
|
||||
m_namep = namep;
|
||||
VerilatedImp::scopeInsert(this);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ typedef WData* WDataOutP; ///< Array output from a function
|
|||
|
||||
class SpTraceVcd;
|
||||
class SpTraceVcdCFile;
|
||||
class VerilatedScope;
|
||||
|
||||
//=========================================================================
|
||||
/// Base class for all Verilated module classes
|
||||
|
|
@ -126,16 +127,37 @@ public:
|
|||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
class VerilatedScope {
|
||||
const char* m_namep; // Scope name
|
||||
public:
|
||||
// Internals - called from VerilatedModule's
|
||||
VerilatedScope() {}
|
||||
~VerilatedScope();
|
||||
void configure(const char* prefixp, const char* suffixp);
|
||||
// Accessors
|
||||
const char* name() const { return m_namep; }
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
struct Verilated {
|
||||
// Extern Vars
|
||||
// Below two are used as bool, but having as uint32_t avoids conversion time
|
||||
// MEMBERS
|
||||
private:
|
||||
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||
static bool s_gotFinish; ///< A $finish statement executed
|
||||
static bool s_assertOn; ///< Assertions are enabled
|
||||
|
||||
static VL_THREAD const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
||||
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
|
||||
static VL_THREAD int t_dpiLineno; ///< DPI context line number
|
||||
|
||||
public:
|
||||
|
||||
// METHODS - User called
|
||||
|
||||
/// Select initial value of otherwise uninitialized signals.
|
||||
////
|
||||
/// 0 = Set to zeros
|
||||
|
|
@ -151,8 +173,6 @@ public:
|
|||
#else
|
||||
static inline int debug() { return 0; } ///< Constant 0 debug, so C++'s optimizer rips up
|
||||
#endif
|
||||
/// Internal: Create a new module name by concatenating two strings
|
||||
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
||||
/// Enable calculation of unused signals
|
||||
static void calcUnusedSigs(bool flag) { s_calcUnusedSigs=flag; }
|
||||
static bool calcUnusedSigs() { return s_calcUnusedSigs; } ///< Return calcUnusedSigs value
|
||||
|
|
@ -166,9 +186,22 @@ public:
|
|||
/// Enable/disable assertions
|
||||
static void assertOn(bool flag) { s_assertOn=flag; }
|
||||
static bool assertOn() { return s_assertOn; }
|
||||
/// Command line arguments
|
||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
||||
static void commandArgs(int argc, const char** argv);
|
||||
static void commandArgs(int argc, char** argv) { commandArgs(argc,(const char**)argv); }
|
||||
|
||||
// METHODS - INTERNAL USE ONLY
|
||||
// Internal: Create a new module name by concatenating two strings
|
||||
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
||||
// Internal: Get and set DPI context
|
||||
static const VerilatedScope* dpiScope() { return t_dpiScopep; }
|
||||
static void dpiScope(const VerilatedScope* scopep) { scopep=t_dpiScopep; }
|
||||
static void dpiContext(const VerilatedScope* scopep, const char* filenamep, int lineno) {
|
||||
t_dpiScopep=scopep; t_dpiFilename=filenamep; t_dpiLineno=lineno; }
|
||||
static void dpiClearContext() { t_dpiScopep = NULL; }
|
||||
static bool dpiInContext() { return t_dpiScopep != NULL; }
|
||||
static const char* dpiFilenamep() { return t_dpiFilename; }
|
||||
static int dpiLineno() { return t_dpiLineno; }
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
|
|
|
|||
|
|
@ -23,19 +23,27 @@
|
|||
///
|
||||
//=========================================================================
|
||||
|
||||
#define _VERILATEDDPI_CPP_
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilatedimp.h"
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
#define _VL_SVDPI_UNIMP()
|
||||
// Not supported yet
|
||||
#define _VL_SVDPI_UNIMP() \
|
||||
vl_fatal(__FILE__,__LINE__,"",Verilated::catName("%%Error: Unsupported DPI function: ",__func__))
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN()
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
VL_PRINTF("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
// DPI ROUTINES
|
||||
|
||||
// Version
|
||||
|
||||
const char* svDpiVersion() {
|
||||
|
|
@ -245,36 +253,39 @@ void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int ind
|
|||
// Functions for working with DPI context
|
||||
|
||||
svScope svGetScope() {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; }
|
||||
return (svScope)Verilated::dpiScope();
|
||||
}
|
||||
|
||||
svScope svSetScope(const svScope scope) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
Verilated::dpiScope(vscopep);
|
||||
return (svScope)vscopep;
|
||||
}
|
||||
|
||||
const char* svGetNameFromScope(const svScope) {
|
||||
_VL_SVDPI_UNIMP(); return "";
|
||||
const char* svGetNameFromScope(const svScope scope) {
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
return vscopep->name();
|
||||
}
|
||||
|
||||
svScope svGetScopeFromName(const char* scopeName) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
return (svScope)VerilatedImp::scopeFind(scopeName);
|
||||
}
|
||||
|
||||
int svPutUserData(const svScope scope, void *userKey, void* userData) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
return -1; // -1 == error
|
||||
VerilatedImp::userInsert(scope,userKey,userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* svGetUserData(const svScope scope, void* userKey) {
|
||||
return NULL; // NULL == error
|
||||
return VerilatedImp::userFind(scope,userKey);
|
||||
}
|
||||
|
||||
int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) {
|
||||
_VL_SVDPI_UNIMP(); return false;
|
||||
//UNSUP if (!Verilated::dpiInContext) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
||||
//UNSUP if (fileNamep) *fileNamepp = Verilated::dpiFilenamep; // thread local
|
||||
//UNSUP if (lineNumberp) *lineNumberp = Verilated::dpiLineno; // thread local
|
||||
//UNSUP return true;
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
||||
if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local
|
||||
if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local
|
||||
return true;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Implementation Header, only for verilated.cpp internals.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
|
||||
#ifndef _VERILATEDIMP_H_
|
||||
#define _VERILATEDIMP_H_ 1 ///< Header Guard
|
||||
|
||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATEDDPI_CPP_)
|
||||
# error "verilatedimp.h only to be included by verilated*.cpp internals"
|
||||
#endif
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
//======================================================================
|
||||
// Types
|
||||
|
||||
struct VerilatedCStrCmp {
|
||||
// For ordering maps keyed by const char*'s
|
||||
bool operator() (const char *a, const char *b) {
|
||||
return std::strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
|
||||
// TYPES
|
||||
typedef vector<string> ArgVec;
|
||||
typedef map<pair<const void*,void*>,void*> UserMap;
|
||||
typedef map<const char*, const VerilatedScope*, VerilatedCStrCmp> ScopeNameMap;
|
||||
|
||||
// MEMBERS
|
||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
ArgVec m_argVec; // Argument list
|
||||
bool m_argVecLoaded; // Ever loaded argument list
|
||||
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
||||
ScopeNameMap m_nameMap; ///< Map of <scope name, scope pointer>
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp() : m_argVecLoaded(false) {}
|
||||
~VerilatedImp() {}
|
||||
|
||||
// METHODS - arguments
|
||||
static void commandArgs(int argc, const char** argv) {
|
||||
s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; i++) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
static string argPlusMatch(const char* prefixp) {
|
||||
int len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
vl_fatal("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// METHODS - user scope tracking
|
||||
// We implement this as a single large map instead of one map per scope
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) {
|
||||
UserMap::iterator it=s_s.m_userMap.find(make_pair(scopep,userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, make_pair(make_pair(scopep,userKey),userData));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) {
|
||||
UserMap::iterator it=s_s.m_userMap.find(make_pair(scopep,userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at construction
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, make_pair(scopep->name(),scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) {
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(namep);
|
||||
if (it != s_s.m_nameMap.end()) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at destruction
|
||||
userEraseScope(scopep);
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
|
|
|
|||
12
src/V3Ast.h
12
src/V3Ast.h
|
|
@ -208,7 +208,9 @@ public:
|
|||
REAL, REALTIME, SHORTINT, SHORTREAL, TIME,
|
||||
// Closer to a class type, but limited usage
|
||||
STRING,
|
||||
// Internal types
|
||||
// Internal types for mid-steps
|
||||
SCOPEPTR, CHARPTR,
|
||||
// Internal types, eliminated after parsing
|
||||
LOGIC_IMPLICIT
|
||||
};
|
||||
enum en m_e;
|
||||
|
|
@ -217,6 +219,7 @@ public:
|
|||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "realtime", "shortint", "shortreal", "time",
|
||||
"string",
|
||||
"VerilatedScope*", "char*",
|
||||
"LOGIC_IMPLICIT"
|
||||
};
|
||||
return names[m_e];
|
||||
|
|
@ -225,6 +228,7 @@ public:
|
|||
static const char* names[] = {
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
"dpiScope", "const char*",
|
||||
"char*",
|
||||
""
|
||||
};
|
||||
|
|
@ -1213,10 +1217,11 @@ public:
|
|||
m_text = textp; // Copy it
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeText)
|
||||
const string& text() const { return m_text; }
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castNodeText()->text(); }
|
||||
const string& text() const { return m_text; }
|
||||
};
|
||||
|
||||
struct AstNodeDType : public AstNode {
|
||||
|
|
@ -1338,6 +1343,9 @@ public:
|
|||
// op2 = Pin interconnection list
|
||||
AstNode* pinsp() const { return op2p()->castNode(); }
|
||||
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
// op3 = scope tracking
|
||||
AstScopeName* scopeNamep() const { return op3p()->castScopeName(); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
|
||||
};
|
||||
|
||||
struct AstNodeModule : public AstNode {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,12 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
|||
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (widthMin() <= 8) {
|
||||
AstBasicDType* bdtypep = basicp();
|
||||
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||
arg += "const char*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||
arg += "const VerilatedScope*";
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "CData";
|
||||
} else if (widthMin() <= 16) {
|
||||
arg += "SData";
|
||||
|
|
@ -296,12 +301,38 @@ void AstScope::cloneRelink() {
|
|||
}
|
||||
|
||||
string AstScope::nameDotless() const {
|
||||
string dotless = shortName();
|
||||
string out = shortName();
|
||||
string::size_type pos;
|
||||
while ((pos=dotless.find(".")) != string::npos) {
|
||||
dotless.replace(pos, 1, "__");
|
||||
while ((pos=out.find(".")) != string::npos) {
|
||||
out.replace(pos, 1, "__");
|
||||
}
|
||||
return dotless;
|
||||
return out;
|
||||
}
|
||||
|
||||
string AstScopeName::scopePrettyName() const {
|
||||
string out;
|
||||
for (AstText* textp=scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
out += textp->text();
|
||||
}
|
||||
// TOP will be replaced by top->name()
|
||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||
return AstNode::prettyName(out);
|
||||
}
|
||||
|
||||
string AstScopeName::scopeSymName() const {
|
||||
string out;
|
||||
for (AstText* textp=scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
out += textp->text();
|
||||
}
|
||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||
string::size_type pos;
|
||||
while ((pos=out.find(".")) != string::npos) {
|
||||
out.replace(pos, 1, "__");
|
||||
}
|
||||
while ((pos=out.find("__DOT__")) != string::npos) {
|
||||
out.replace(pos, 7, "__");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool AstSenTree::hasClocked() {
|
||||
|
|
@ -560,6 +591,17 @@ void AstTraceInc::dump(ostream& str) {
|
|||
if (declp()) { declp()->dump(str); }
|
||||
else { str<<"%Error:UNLINKED"; }
|
||||
}
|
||||
void AstNodeText::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
string out = text();
|
||||
string::size_type pos;
|
||||
if ((pos = out.find("\n")) != string::npos) {
|
||||
out.erase(pos,out.length()-pos);
|
||||
out += "...";
|
||||
}
|
||||
str<<" \""<<out<<"\"";
|
||||
}
|
||||
|
||||
void AstCFile::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (source()) str<<" [SRC]";
|
||||
|
|
|
|||
|
|
@ -612,6 +612,7 @@ struct AstScope : public AstNode {
|
|||
// Parents: MODULE
|
||||
// Children: NODEBLOCK
|
||||
private:
|
||||
// An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope
|
||||
string m_name; // Name
|
||||
AstScope* m_aboveScopep; // Scope above this one in the hierarchy (NULL if top)
|
||||
AstCell* m_aboveCellp; // Cell above this in the hierarchy (NULL if top)
|
||||
|
|
@ -2001,17 +2002,22 @@ public:
|
|||
virtual void dump(ostream& str=cout);
|
||||
};
|
||||
|
||||
struct AstScopeName : public AstNode {
|
||||
// For display %m
|
||||
struct AstScopeName : public AstNodeMath {
|
||||
// For display %m and DPI context imports
|
||||
// Parents: DISPLAY
|
||||
// Children: TEXT
|
||||
AstScopeName(FileLine* fl)
|
||||
: AstNode(fl) {}
|
||||
AstScopeName(FileLine* fl) : AstNodeMath(fl) {
|
||||
width(64,64); }
|
||||
ASTNODE_NODE_FUNCS(ScopeName, SCOPENAME)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual string emitVerilog() { return ""; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
AstText* scopeAttrp() const { return op1p()->castText(); }
|
||||
void scopeAttrp(AstNode* nodep) { addOp1p(nodep); }
|
||||
string scopeSymName() const; // Name for __Vscope variable including children
|
||||
string scopePrettyName() const; // Name for __Vscope printing
|
||||
};
|
||||
|
||||
struct AstUdpTable : public AstNode {
|
||||
|
|
@ -3177,9 +3183,12 @@ public:
|
|||
addNOp1p(argsp);
|
||||
}
|
||||
AstCCall(AstCCall* oldp, AstCFunc* funcp) // Replacement form for V3Combine
|
||||
// Note this removes old attachments from the oldp
|
||||
: AstNodeStmt(oldp->fileline()) {
|
||||
m_funcp = funcp;
|
||||
m_hiername = oldp->hiername();
|
||||
m_argTypes = oldp->argTypes();
|
||||
if (oldp->argsp()) addNOp1p(oldp->argsp()->unlinkFrBackWithNext());
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(CCall, CCALL)
|
||||
virtual void dump(ostream& str=cout);
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ private:
|
|||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_namedScope)));
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_namedScope));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ protected:
|
|||
//***** optimization levels
|
||||
bool emptyFunctionDeletion() { return true; }
|
||||
bool duplicateFunctionCombine() { return true; }
|
||||
// Note this is disabled, it still needed work
|
||||
// Also repair it for DPI functions; when make __common need to insure proper
|
||||
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
|
||||
// get split between functions causing the text to have a danginling reference.
|
||||
bool statementCombine() { return false && duplicateFunctionCombine(); }
|
||||
};
|
||||
|
||||
|
|
@ -101,7 +105,7 @@ public:
|
|||
if (callp->funcp() != oldfuncp) callp->v3fatalSrc("Call list broken, points to call w/different func");
|
||||
if (newfuncp) {
|
||||
AstCCall* newp = new AstCCall(callp, newfuncp);
|
||||
newp->argTypes(callp->argTypes());
|
||||
// Special new AstCCall form above transfers children of callp to newfuncp
|
||||
callp->replaceWith(newp);
|
||||
addCall(newp); // Fix the table
|
||||
} else { // Just deleting empty function
|
||||
|
|
|
|||
|
|
@ -223,6 +223,10 @@ public:
|
|||
if (nodep->addNewline()) text += "\n";
|
||||
displayNode(nodep, text, nodep->exprsp(), false);
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
// For use under AstCCalls for dpiImports. ScopeNames under displays are handled in AstDisplay
|
||||
putbs("(&(vlSymsp->__Vscope_"+nodep->scopeSymName()+"))");
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep, AstNUser*) {
|
||||
displayNode(nodep, nodep->text(), nodep->exprsp(), false);
|
||||
}
|
||||
|
|
@ -1198,9 +1202,7 @@ void EmitCStmts::displayNode(AstNode* nodep, const string& vformat, AstNode* exp
|
|||
if (!nodep->castNodeDisplay()) nodep->v3fatalSrc("Non-Display with %m");
|
||||
AstScopeName* scopenamep = nodep->castNodeDisplay()->scopeNamep();
|
||||
if (!scopenamep) nodep->v3fatalSrc("Display with %m but no AstScopeName");
|
||||
for (AstText* textp=scopenamep->scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
emitDispState.pushFormat(textp->text());
|
||||
}
|
||||
emitDispState.pushFormat(scopenamep->scopePrettyName());
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
|
|
|
|||
|
|
@ -44,10 +44,13 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
// AstNodeModule::user1() -> bool. Set true __Vconfigure called
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
typedef map<string,AstScopeName*> ScopeNames;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
||||
vector<ScopeModPair> m_scopes; // Every scope by module
|
||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
||||
V3LanguageWords m_words; // Reserved word detector
|
||||
int m_coverBins; // Coverage bin number
|
||||
|
||||
|
|
@ -94,6 +97,12 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
nameCheck(nodep);
|
||||
m_scopes.push_back(make_pair(nodep, m_modp));
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
string name = nodep->scopeSymName();
|
||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||
m_scopeNames.insert(make_pair(name, nodep));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||
|
|
@ -101,7 +110,6 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||
}
|
||||
}
|
||||
// NOPs
|
||||
virtual void visit(AstNodeStmt*, AstNUser*) {}
|
||||
virtual void visit(AstConst*, AstNUser*) {}
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
|
|
@ -174,6 +182,11 @@ void EmitCSyms::emitInt() {
|
|||
puts("uint32_t\t__Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
|
||||
}
|
||||
|
||||
puts("\n// SCOPE NAMES\n");
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
puts("VerilatedScope __Vscope_"+it->second->scopeSymName()+";\n");
|
||||
}
|
||||
|
||||
puts("\n// CREATORS\n");
|
||||
puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n");
|
||||
puts((string)"~"+symClassName()+"() {};\n");
|
||||
|
|
@ -242,6 +255,7 @@ void EmitCSyms::emitImp() {
|
|||
puts(scopep->nameDotless()+";\n");
|
||||
}
|
||||
}
|
||||
|
||||
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
|
||||
puts("TOPp->__Vconfigure(this, true);\n");
|
||||
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
|
|
@ -256,6 +270,13 @@ void EmitCSyms::emitImp() {
|
|||
}
|
||||
}
|
||||
|
||||
puts("// Setup scope names\n");
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
puts("__Vscope_"+it->second->scopeSymName()+".configure(name(),");
|
||||
putsQuoted(it->second->scopePrettyName());
|
||||
puts(");\n");
|
||||
}
|
||||
|
||||
puts("}\n");
|
||||
puts("\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public:
|
|||
: GateEitherVertex(graphp,scopep), m_nodep(nodep), m_activep(activep), m_slow(slow) {}
|
||||
virtual ~GateLogicVertex() {}
|
||||
// Accessors
|
||||
virtual string name() const { return (cvtToStr((void*)m_nodep)+"@"+scopep()->name()); }
|
||||
virtual string name() const { return (cvtToStr((void*)m_nodep)+"@"+scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return "yellow"; }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstActive* activep() const { return m_activep; }
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ private:
|
|||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+m_cellp->prettyName()));
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,12 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
m_ftaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->taskp() && nodep->taskp()->dpiContext()) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
// Remove bit selects, and bark if it's not a simple variable
|
||||
|
|
|
|||
|
|
@ -211,16 +211,14 @@ private:
|
|||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
string prefix = (string)(".")+m_scopep->prettyName();
|
||||
string prefix = (string)("__DOT__")+m_scopep->name();
|
||||
// TOP and above will be the user's name().
|
||||
// Note 'TOP.'is stripped by prettyName, but not 'TOP'.
|
||||
if (prefix != ".TOP") {
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
// Note 'TOP.' is stripped by scopePrettyName
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,9 @@ private:
|
|||
virtual void visit(AstLogIf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstLogIff* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
// ... These shouldn't matter, just make unsigned
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
// ... These comparisons don't care about inbound types
|
||||
// ... (Though they should match. We don't check.)
|
||||
virtual void visit(AstEq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
|
|
|
|||
|
|
@ -324,6 +324,16 @@ private:
|
|||
return level;
|
||||
}
|
||||
|
||||
AstVarScope* createInputVar(AstCFunc* funcp, const string& name, AstBasicDTypeKwd kwd) {
|
||||
AstVar* newvarp = new AstVar (funcp->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
new AstBasicDType(funcp->fileline(), kwd));
|
||||
newvarp->funcLocal(true);
|
||||
newvarp->combineType(AstVarType::INPUT);
|
||||
funcp->addArgsp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
return newvscp;
|
||||
}
|
||||
AstVarScope* createVarScope(AstVar* invarp, const string& name) {
|
||||
// We could create under either the ref's scope or the ftask's scope.
|
||||
// It shouldn't matter, as they are only local variables.
|
||||
|
|
@ -491,8 +501,19 @@ private:
|
|||
}
|
||||
}
|
||||
// First argument is symbol table, then output if a function
|
||||
bool needContext = !refp->taskp()->dpiImport() || refp->taskp()->dpiContext();
|
||||
if (needContext) ccallp->argTypes("vlSymsp");
|
||||
bool needSyms = !refp->taskp()->dpiImport();
|
||||
if (needSyms) ccallp->argTypes("vlSymsp");
|
||||
|
||||
if (refp->taskp()->dpiContext()) {
|
||||
// __Vscopep
|
||||
AstNode* snp = refp->scopeNamep()->unlinkFrBack(); if (!snp) refp->v3fatalSrc("Missing scoping context");
|
||||
ccallp->addArgsp(snp);
|
||||
// __Vfilenamep
|
||||
ccallp->addArgsp(new AstCMath(refp->fileline(), "\""+refp->fileline()->filename()+"\"", 64, true));
|
||||
// __Vlineno
|
||||
ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno()));
|
||||
}
|
||||
|
||||
if (outvscp) {
|
||||
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
|
||||
}
|
||||
|
|
@ -536,7 +557,10 @@ private:
|
|||
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
AstVarScope* portvscp = portp->user2p()->castNode()->castVarScope(); // Remembered when we created it earlier
|
||||
if (portp->isIO() && !portp->isFuncReturn() && portvscp != rtnvscp) {
|
||||
if (portp->isIO() && !portp->isFuncReturn() && portvscp != rtnvscp
|
||||
&& portp->name() != "__Vscopep" // Passed to dpiContext, not callee
|
||||
&& portp->name() != "__Vfilenamep"
|
||||
&& portp->name() != "__Vlineno") {
|
||||
bool bitvec = (portp->basicp()->isBitLogic() && portp->width() > 32);
|
||||
|
||||
if (args != "") { args+= ", "; }
|
||||
|
|
@ -576,7 +600,8 @@ private:
|
|||
|
||||
// Store context, if needed
|
||||
if (nodep->dpiContext()) {
|
||||
// TBD
|
||||
string stmt = "Verilated::dpiContext(__Vscopep, __Vfilenamep, __Vlineno);\n";
|
||||
cfuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
|
||||
{// Call the user function
|
||||
|
|
@ -640,8 +665,11 @@ private:
|
|||
string prefix = "";
|
||||
if (nodep->dpiImport()) prefix = "__Vdpiimwrap_";
|
||||
else if (ftaskNoInline) prefix = "__VnoInFunc_";
|
||||
// Unless public, v3Descope will not uniquify function names even if duplicate per-scope.
|
||||
string suffix = ""; // So, make them unique
|
||||
if (!nodep->taskPublic()) suffix = "_"+m_scopep->nameDotless();
|
||||
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
|
||||
prefix + nodep->name(),
|
||||
prefix + nodep->name() + suffix,
|
||||
m_scopep,
|
||||
((nodep->taskPublic() && rtnvarp)?rtnvarp->cpubArgType(true,true):""));
|
||||
// It's ok to combine imports because this is just a wrapper; duplicate wrappers can get merged.
|
||||
|
|
@ -652,8 +680,8 @@ private:
|
|||
cfuncp->pure (nodep->pure());
|
||||
//cfuncp->dpiImport // Not set in the wrapper - the called function has it set
|
||||
|
||||
bool needContext = !nodep->dpiImport() || nodep->dpiContext();
|
||||
if (needContext) {
|
||||
bool needSyms = !nodep->dpiImport();
|
||||
if (needSyms) {
|
||||
if (nodep->taskPublic()) {
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
cfuncp->addInitsp(
|
||||
|
|
@ -664,6 +692,13 @@ private:
|
|||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
}
|
||||
}
|
||||
if (nodep->dpiContext()) {
|
||||
// First three args go to dpiContext call
|
||||
createInputVar (cfuncp, "__Vscopep", AstBasicDTypeKwd::SCOPEPTR);
|
||||
createInputVar (cfuncp, "__Vfilenamep", AstBasicDTypeKwd::CHARPTR);
|
||||
createInputVar (cfuncp, "__Vlineno", AstBasicDTypeKwd::INT);
|
||||
}
|
||||
|
||||
// Fake output variable if was a function
|
||||
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
||||
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ private:
|
|||
nodep->width(selwidth,selwidth);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->width(32,1); // Approximation, unsized 32
|
||||
}
|
||||
|
|
@ -489,7 +489,7 @@ private:
|
|||
// Only used in CStmts which don't care....
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser* vup) {
|
||||
// Only used in Displays which don't care....
|
||||
nodep->width(64,1); // A pointer, but not that it matters
|
||||
}
|
||||
virtual void visit(AstArrayDType* nodep, AstNUser* vup) {
|
||||
// Lower datatype determines the width
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["t/t_dpi_context_c.cpp"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t ();
|
||||
|
||||
sub a (.inst(1));
|
||||
sub b (.inst(2));
|
||||
|
||||
initial begin
|
||||
a.test1;
|
||||
b.test1;
|
||||
a.test2;
|
||||
b.test2;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module sub (input integer inst);
|
||||
|
||||
import "DPI-C" context function int dpic_line();
|
||||
import "DPI-C" context function int dpic_save(int value);
|
||||
import "DPI-C" context function int dpic_restore();
|
||||
|
||||
int result;
|
||||
|
||||
task test1;
|
||||
// Check line numbering
|
||||
`ifndef verilator // Not all sims support SV2009 `__LINE__, and some that do fail the specific-line test
|
||||
result = dpic_line(); if (!result) $stop;
|
||||
`else
|
||||
result = dpic_line(); if (result !== `__LINE__) $stop;
|
||||
//
|
||||
result = dpic_line(); if (result !== `__LINE__) $stop;
|
||||
`endif
|
||||
|
||||
// Check save-restore
|
||||
result = dpic_save(23+inst);
|
||||
if (result==0) $stop;
|
||||
endtask
|
||||
|
||||
task test2;
|
||||
if (dpic_restore() != 23+inst) $stop;
|
||||
endtask
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include <stdio.h>
|
||||
#include <svdpi.h>
|
||||
|
||||
//======================================================================
|
||||
|
||||
#if defined(VERILATOR)
|
||||
# ifdef T_DPI_CONTEXT_NOOPT
|
||||
# include "Vt_dpi_context_noopt__Dpi.h"
|
||||
# else
|
||||
# include "Vt_dpi_context__Dpi.h"
|
||||
# endif
|
||||
#elif defined(VCS)
|
||||
# include "../vc_hdrs.h"
|
||||
#elif defined(CADENCE)
|
||||
# define NEED_EXTERNS
|
||||
#else
|
||||
# error "Unknown simulator for DPI test"
|
||||
#endif
|
||||
|
||||
#ifdef NEED_EXTERNS
|
||||
extern "C" {
|
||||
|
||||
extern int dpic_line();
|
||||
extern int dpic_save(int value);
|
||||
extern int dpic_restore();
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
int dpic_line() {
|
||||
svScope scope = svGetScope();
|
||||
if (!scope) {
|
||||
printf("%%Warning: svGetScope failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* scopenamep = svGetNameFromScope(scope);
|
||||
if (!scopenamep) {
|
||||
printf("%%Warning: svGetNameFromScope failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (scope != svGetScopeFromName(scopenamep)) {
|
||||
printf("%%Warning: svGetScopeFromName repeat failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* filenamep = "";
|
||||
int lineno = 0;
|
||||
if (svGetCallerInfo(&filenamep, &lineno)) {
|
||||
printf("Call from %s:%d:%s\n", filenamep, lineno, scopenamep);
|
||||
} else {
|
||||
printf("%%Warning: svGetCallerInfo failed\n");
|
||||
return 0;
|
||||
}
|
||||
return lineno;
|
||||
}
|
||||
|
||||
extern int Dpic_Unique;
|
||||
int Dpic_Unique = 0; // Address used for uniqueness
|
||||
|
||||
int dpic_save(int value) {
|
||||
svScope scope = svGetScope();
|
||||
if (!scope) {
|
||||
printf("%%Warning: svGetScope failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svPutUserData(scope, &Dpic_Unique, (void*)(value))) {
|
||||
printf("%%Warning: svPutUserData failed\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dpic_restore() {
|
||||
svScope scope = svGetScope();
|
||||
if (!scope) {
|
||||
printf("%%Warning: svGetScope failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (void* userp = svGetUserData(scope, &Dpic_Unique)) {
|
||||
return (int)(long long)(userp);
|
||||
} else {
|
||||
printf("%%Warning: svGetUserData failed\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
top_filename("t/t_dpi_context.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => ["t/t_dpi_context_c.cpp"],
|
||||
verilator_flags2 => [$Self->{v3}?"-O0":""],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -54,9 +54,6 @@ module t ();
|
|||
import "DPI-C" dpii_fa_bit = function int oth_f_int1(input int i);
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int2(input int i);
|
||||
|
||||
// Try context
|
||||
import "DPI-C" context function int dpii_context();
|
||||
|
||||
bit i_b, o_b;
|
||||
bit [7:0] i_b8, o_b8;
|
||||
bit [8:0] i_b9, o_b9;
|
||||
|
|
@ -131,12 +128,6 @@ module t ();
|
|||
if (oth_f_int1(32'd123) !== ~32'd123) $stop;
|
||||
if (oth_f_int2(32'd124) !== ~32'd124) $stop;
|
||||
|
||||
`ifndef verilator // Not all sims support SV2009 `__LINE__, and some that do fail the specific-line test
|
||||
if (!dpii_context()) $stop;
|
||||
`else
|
||||
//UNSUP if (dpii_context() !== `__LINE__) $stop;
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ extern "C" {
|
|||
extern int dpii_t_int (int i, int *o);
|
||||
|
||||
extern int dpii_fa_bit(int i);
|
||||
|
||||
extern int dpii_context();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -109,13 +107,3 @@ int dpii_t_int (int i, int *o) {
|
|||
int dpii_fa_bit (int i) {
|
||||
return ~i;
|
||||
}
|
||||
|
||||
int dpii_context() {
|
||||
const char* filename = "";
|
||||
int lineno = 0;
|
||||
if (svGetCallerInfo(&filename, &lineno)) {
|
||||
return lineno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue