include: Merge misc thread runtime support.
This commit is contained in:
parent
2c568603f6
commit
fe917ba7f4
|
|
@ -202,7 +202,7 @@ IData VL_RAND32() VL_MT_SAFE {
|
||||||
t_seeded = true;
|
t_seeded = true;
|
||||||
long seedval;
|
long seedval;
|
||||||
{
|
{
|
||||||
VerilatedLockGuard guard(s_mutex);
|
VerilatedLockGuard lock(s_mutex);
|
||||||
seedval = lrand48()<<16 ^ lrand48();
|
seedval = lrand48()<<16 ^ lrand48();
|
||||||
if (!seedval) seedval++;
|
if (!seedval) seedval++;
|
||||||
}
|
}
|
||||||
|
|
@ -1612,7 +1612,7 @@ Verilated::ThreadLocal::~ThreadLocal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::debug(int val) VL_MT_SAFE {
|
void Verilated::debug(int val) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_debug = val;
|
s_s.s_debug = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
|
|
@ -1623,23 +1623,23 @@ void Verilated::debug(int val) VL_MT_SAFE {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Verilated::randReset(int val) VL_MT_SAFE {
|
void Verilated::randReset(int val) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_randReset = val;
|
s_s.s_randReset = val;
|
||||||
}
|
}
|
||||||
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_calcUnusedSigs = flag;
|
s_s.s_calcUnusedSigs = flag;
|
||||||
}
|
}
|
||||||
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_gotFinish = flag;
|
s_s.s_gotFinish = flag;
|
||||||
}
|
}
|
||||||
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_assertOn = flag;
|
s_s.s_assertOn = flag;
|
||||||
}
|
}
|
||||||
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_s.s_fatalOnVpiError = flag;
|
s_s.s_fatalOnVpiError = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1661,7 +1661,7 @@ const char* Verilated::catName(const char* n1, const char* n2) VL_MT_SAFE {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
if (s_flushCb == cb) {} // Ok - don't duplicate
|
if (s_flushCb == cb) {} // Ok - don't duplicate
|
||||||
else if (!s_flushCb) { s_flushCb=cb; }
|
else if (!s_flushCb) { s_flushCb=cb; }
|
||||||
else {
|
else {
|
||||||
|
|
@ -1671,14 +1671,14 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::flushCall() VL_MT_SAFE {
|
void Verilated::flushCall() VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
if (s_flushCb) (*s_flushCb)();
|
if (s_flushCb) (*s_flushCb)();
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
s_args.argc = argc;
|
s_args.argc = argc;
|
||||||
s_args.argv = argv;
|
s_args.argv = argv;
|
||||||
VerilatedImp::commandArgs(argc,argv);
|
VerilatedImp::commandArgs(argc,argv);
|
||||||
|
|
@ -1716,16 +1716,6 @@ void Verilated::scopesDump() VL_MT_SAFE {
|
||||||
VerilatedImp::scopesDump();
|
VerilatedImp::scopesDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verilated::numThreads(unsigned threads) VL_MT_SAFE {
|
|
||||||
VerilatedImp::numThreads(threads);
|
|
||||||
}
|
|
||||||
unsigned Verilated::numThreads() VL_MT_SAFE {
|
|
||||||
return VerilatedImp::numThreads();
|
|
||||||
}
|
|
||||||
void Verilated::spawnThreads() VL_MT_SAFE {
|
|
||||||
VerilatedImp::spawnThreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
const VerilatedScope* Verilated::scopeFind(const char* namep) VL_MT_SAFE {
|
const VerilatedScope* Verilated::scopeFind(const char* namep) VL_MT_SAFE {
|
||||||
return VerilatedImp::scopeFind(namep);
|
return VerilatedImp::scopeFind(namep);
|
||||||
}
|
}
|
||||||
|
|
@ -1948,7 +1938,7 @@ void VerilatedScope::scopeDump() const {
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// VerilatedOneThreaded:: Methods
|
// VerilatedOneThreaded:: Methods
|
||||||
|
|
||||||
#ifdef VL_THREADED
|
#if defined(VL_THREADED) && defined(VL_DEBUG)
|
||||||
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
|
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Routine called that is single threaded, but called from"
|
VL_FATAL_MT(__FILE__, __LINE__, "", "Routine called that is single threaded, but called from"
|
||||||
" a different thread then the expected constructing thread");
|
" a different thread then the expected constructing thread");
|
||||||
|
|
|
||||||
|
|
@ -437,17 +437,6 @@ public:
|
||||||
/// releases - contact the authors before production use.
|
/// releases - contact the authors before production use.
|
||||||
static void scopesDump() VL_MT_SAFE;
|
static void scopesDump() VL_MT_SAFE;
|
||||||
|
|
||||||
/// Set the number of threads to execute on.
|
|
||||||
/// 0x0 = use all available CPU threads, or 1 if no support compiled in
|
|
||||||
/// Ignored after spawnThreads() has been called
|
|
||||||
static void numThreads(unsigned threads) VL_MT_SAFE;
|
|
||||||
static unsigned numThreads() VL_MT_SAFE;
|
|
||||||
/// Spawn child threads, using numThreads() as # of threads
|
|
||||||
/// Verilator calls this automatically on the first eval() call
|
|
||||||
/// User code may call it earlier if desired
|
|
||||||
/// Once called the first time, later calls are ignored
|
|
||||||
static void spawnThreads() VL_MT_SAFE;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
||||||
// Internal: Create a new module name by concatenating two strings
|
// Internal: Create a new module name by concatenating two strings
|
||||||
|
|
|
||||||
|
|
@ -233,12 +233,12 @@ public:
|
||||||
// PUBLIC METHODS
|
// PUBLIC METHODS
|
||||||
void clear() VL_EXCLUDES(m_mutex) {
|
void clear() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
clearGuts();
|
clearGuts();
|
||||||
}
|
}
|
||||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
if (matchp && matchp[0]) {
|
if (matchp && matchp[0]) {
|
||||||
ItemList newlist;
|
ItemList newlist;
|
||||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
|
|
@ -254,7 +254,7 @@ public:
|
||||||
}
|
}
|
||||||
void zero() VL_EXCLUDES(m_mutex) {
|
void zero() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
(*it)->zero();
|
(*it)->zero();
|
||||||
}
|
}
|
||||||
|
|
@ -262,18 +262,18 @@ public:
|
||||||
|
|
||||||
// We assume there's always call to i/f/p in that order
|
// We assume there's always call to i/f/p in that order
|
||||||
void inserti (VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
void inserti (VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
assert(!m_insertp);
|
assert(!m_insertp);
|
||||||
m_insertp = itemp;
|
m_insertp = itemp;
|
||||||
}
|
}
|
||||||
void insertf (const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
void insertf (const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_insertFilenamep = filenamep;
|
m_insertFilenamep = filenamep;
|
||||||
m_insertLineno = lineno;
|
m_insertLineno = lineno;
|
||||||
}
|
}
|
||||||
void insertp (const char* ckeyps[MAX_KEYS],
|
void insertp (const char* ckeyps[MAX_KEYS],
|
||||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
assert(m_insertp);
|
assert(m_insertp);
|
||||||
// First two key/vals are filename
|
// First two key/vals are filename
|
||||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||||
|
|
@ -328,7 +328,7 @@ public:
|
||||||
|
|
||||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
#ifndef VM_COVERAGE
|
#ifndef VM_COVERAGE
|
||||||
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ public:
|
||||||
// METHODS
|
// METHODS
|
||||||
//// Add message to queue (called by producer)
|
//// Add message to queue (called by producer)
|
||||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard guard(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||||
++m_depth;
|
++m_depth;
|
||||||
}
|
}
|
||||||
|
|
@ -199,15 +199,10 @@ class VerilatedImp {
|
||||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||||
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||||
|
|
||||||
// Threads
|
|
||||||
VerilatedMutex m_threadMutex; ///< Protect m_numThreads, etc
|
|
||||||
bool m_spawned VL_GUARDED_BY(m_threadMutex); ///< Already called spawnThreads()
|
|
||||||
unsigned m_numThreads VL_GUARDED_BY(m_threadMutex); ///< Number of threads user requested, 0x0=all cpus
|
|
||||||
|
|
||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedImp()
|
VerilatedImp()
|
||||||
: m_argVecLoaded(false), m_exportNext(0), m_spawned(false), m_numThreads(0) {
|
: m_argVecLoaded(false), m_exportNext(0) {
|
||||||
m_fdps.resize(3);
|
m_fdps.resize(3);
|
||||||
m_fdps[0] = stdin;
|
m_fdps[0] = stdin;
|
||||||
m_fdps[1] = stdout;
|
m_fdps[1] = stdout;
|
||||||
|
|
@ -218,7 +213,7 @@ private:
|
||||||
VL_UNCOPYABLE(VerilatedImp);
|
VL_UNCOPYABLE(VerilatedImp);
|
||||||
public:
|
public:
|
||||||
static void internalsDump() VL_MT_SAFE {
|
static void internalsDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
VL_PRINTF_MT("internalsDump:\n");
|
VL_PRINTF_MT("internalsDump:\n");
|
||||||
VL_PRINTF_MT(" Argv:");
|
VL_PRINTF_MT(" Argv:");
|
||||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||||
|
|
@ -234,16 +229,16 @@ public:
|
||||||
// METHODS - arguments
|
// METHODS - arguments
|
||||||
public:
|
public:
|
||||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
s_s.m_argVec.clear(); // Always clear
|
s_s.m_argVec.clear(); // Always clear
|
||||||
commandArgsAddGuts(argc, argv);
|
commandArgsAddGuts(argc, argv);
|
||||||
}
|
}
|
||||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
commandArgsAddGuts(argc, argv);
|
commandArgsAddGuts(argc, argv);
|
||||||
}
|
}
|
||||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
// Note prefixp does not include the leading "+"
|
// Note prefixp does not include the leading "+"
|
||||||
size_t len = strlen(prefixp);
|
size_t len = strlen(prefixp);
|
||||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||||
|
|
@ -272,14 +267,14 @@ public:
|
||||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
// 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.
|
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
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
|
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
||||||
}
|
}
|
||||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||||
else return NULL;
|
else return NULL;
|
||||||
|
|
@ -288,7 +283,7 @@ private:
|
||||||
/// Symbol table destruction cleans up the entries for each scope.
|
/// Symbol table destruction cleans up the entries for each scope.
|
||||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||||
if (it->first.first == scopep) {
|
if (it->first.first == scopep) {
|
||||||
s_s.m_userMap.erase(it++);
|
s_s.m_userMap.erase(it++);
|
||||||
|
|
@ -298,7 +293,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void userDump() VL_MT_SAFE {
|
static void userDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||||
|
|
@ -311,27 +306,27 @@ public: // But only for verilated*.cpp
|
||||||
// METHODS - scope name
|
// METHODS - scope name
|
||||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at construction
|
// Slow ok - called once/scope at construction
|
||||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||||
if (it == s_s.m_nameMap.end()) {
|
if (it == s_s.m_nameMap.end()) {
|
||||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||||
else return NULL;
|
else return NULL;
|
||||||
}
|
}
|
||||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at destruction
|
// Slow ok - called once/scope at destruction
|
||||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
userEraseScope(scopep);
|
userEraseScope(scopep);
|
||||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||||
}
|
}
|
||||||
static void scopesDump() VL_MT_SAFE {
|
static void scopesDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VL_PRINTF_MT(" scopesDump:\n");
|
VL_PRINTF_MT(" scopesDump:\n");
|
||||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||||
const VerilatedScope* scopep = it->second;
|
const VerilatedScope* scopep = it->second;
|
||||||
|
|
@ -355,7 +350,7 @@ public: // But only for verilated*.cpp
|
||||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/function at creation
|
// Slow ok - called once/function at creation
|
||||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||||
if (it == s_s.m_exportMap.end()) {
|
if (it == s_s.m_exportMap.end()) {
|
||||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||||
|
|
@ -365,7 +360,7 @@ public: // But only for verilated*.cpp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||||
|
|
@ -375,14 +370,14 @@ public: // But only for verilated*.cpp
|
||||||
}
|
}
|
||||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||||
if (it->second == funcnum) return it->first;
|
if (it->second == funcnum) return it->first;
|
||||||
}
|
}
|
||||||
return "*UNKNOWN*";
|
return "*UNKNOWN*";
|
||||||
}
|
}
|
||||||
static void exportsDump() VL_MT_SAFE {
|
static void exportsDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||||
|
|
@ -397,7 +392,7 @@ public: // But only for verilated*.cpp
|
||||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||||
if (VL_UNLIKELY(!fp)) return 0;
|
if (VL_UNLIKELY(!fp)) return 0;
|
||||||
// Bit 31 indicates it's a descriptor not a MCD
|
// Bit 31 indicates it's a descriptor not a MCD
|
||||||
VerilatedLockGuard guard(s_s.m_fdMutex);
|
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
if (s_s.m_fdFree.empty()) {
|
if (s_s.m_fdFree.empty()) {
|
||||||
// Need to create more space in m_fdps and m_fdFree
|
// Need to create more space in m_fdps and m_fdFree
|
||||||
size_t start = s_s.m_fdps.size();
|
size_t start = s_s.m_fdps.size();
|
||||||
|
|
@ -410,7 +405,7 @@ public: // But only for verilated*.cpp
|
||||||
}
|
}
|
||||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
IData idx = VL_MASK_I(31) & fdi;
|
||||||
VerilatedLockGuard guard(s_s.m_fdMutex);
|
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||||
s_s.m_fdps[idx] = NULL;
|
s_s.m_fdps[idx] = NULL;
|
||||||
|
|
@ -418,41 +413,10 @@ public: // But only for verilated*.cpp
|
||||||
}
|
}
|
||||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
IData idx = VL_MASK_I(31) & fdi;
|
||||||
VerilatedLockGuard guard(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||||
return s_s.m_fdps[idx];
|
return s_s.m_fdps[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // But only for verilated*.cpp
|
|
||||||
// METHODS - Threading
|
|
||||||
static void numThreads(unsigned threads) VL_MT_SAFE {
|
|
||||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
|
||||||
if (!s_s.m_spawned) s_s.m_numThreads = threads;
|
|
||||||
}
|
|
||||||
static unsigned numThreads() VL_MT_SAFE {
|
|
||||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
|
||||||
#ifdef VL_THREADED
|
|
||||||
unsigned threads = s_s.m_numThreads;
|
|
||||||
if (threads == 0x0) {
|
|
||||||
threads = std::thread::hardware_concurrency(); // Or 0=unknown, C++11
|
|
||||||
}
|
|
||||||
if (threads<1) threads = 1;
|
|
||||||
return threads;
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
static void spawnThreads() VL_MT_SAFE {
|
|
||||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
|
||||||
if (!s_s.m_spawned) {
|
|
||||||
// Convert numThreads from 0 to the spawned number
|
|
||||||
numThreads(numThreads());
|
|
||||||
s_s.m_spawned = true;
|
|
||||||
#ifdef VL_THREADED
|
|
||||||
// THREADED-TODO startup threads
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
|
||||||
|
|
@ -61,18 +61,18 @@ private:
|
||||||
static Singleton& singleton() { static Singleton s; return s; }
|
static Singleton& singleton() { static Singleton s; return s; }
|
||||||
public:
|
public:
|
||||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||||
singleton().s_vcdVecp.push_back(vcdp);
|
singleton().s_vcdVecp.push_back(vcdp);
|
||||||
}
|
}
|
||||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||||
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
||||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||||
}
|
}
|
||||||
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
||||||
// Thread safety: Although this function is protected by a mutex so perhaps
|
// Thread safety: Although this function is protected by a mutex so perhaps
|
||||||
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
|
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
|
||||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||||
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
|
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
|
||||||
VerilatedVcd* vcdp = *it;
|
VerilatedVcd* vcdp = *it;
|
||||||
vcdp->flush();
|
vcdp->flush();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue