mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Handle correctly
This commit is contained in:
@@ -2926,6 +2926,20 @@ std::string VerilatedContext::dumpfileCheck() const VL_MT_SAFE_EXCLUDES(m_timeDu
|
||||
}
|
||||
return out;
|
||||
}
|
||||
void VerilatedContext::dumpvarsAdd(int level,
|
||||
const std::string& hier) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) {
|
||||
const VerilatedLockGuard lock{m_timeDumpMutex};
|
||||
if (level == 0 && hier.empty()) {
|
||||
m_dumpvars.clear();
|
||||
} else {
|
||||
m_dumpvars.emplace_back(level, hier);
|
||||
}
|
||||
}
|
||||
std::vector<VerilatedTraceDumpvarsEntry>
|
||||
VerilatedContext::dumpvars() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) {
|
||||
const VerilatedLockGuard lock{m_timeDumpMutex};
|
||||
return m_dumpvars;
|
||||
}
|
||||
void VerilatedContext::errorCount(int val) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_s.m_errorCount = val;
|
||||
|
||||
@@ -110,6 +110,15 @@ class VerilatedVcd;
|
||||
class VerilatedVcdC;
|
||||
class VerilatedVcdSc;
|
||||
|
||||
struct VerilatedTraceDumpvarsEntry final {
|
||||
int m_level;
|
||||
std::string m_hier;
|
||||
|
||||
VerilatedTraceDumpvarsEntry(int level, const std::string& hier)
|
||||
: m_level{level}
|
||||
, m_hier{hier} {}
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
// Basic types
|
||||
|
||||
@@ -404,6 +413,8 @@ protected:
|
||||
mutable VerilatedMutex m_timeDumpMutex; // Protect misc slow strings
|
||||
std::string m_timeFormatSuffix VL_GUARDED_BY(m_timeDumpMutex); // $timeformat printf format
|
||||
std::string m_dumpfile VL_GUARDED_BY(m_timeDumpMutex); // $dumpfile setting
|
||||
std::vector<VerilatedTraceDumpvarsEntry>
|
||||
m_dumpvars VL_GUARDED_BY(m_timeDumpMutex); // $dumpvars settings
|
||||
|
||||
struct NonSerialized final { // Non-serialized information
|
||||
// These are reloaded from on command-line settings, so do not need to persist
|
||||
@@ -656,6 +667,11 @@ public:
|
||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
std::string dumpfileCheck() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
|
||||
// Internal: $dumpvars
|
||||
void dumpvarsAdd(int level, const std::string& hier) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
std::vector<VerilatedTraceDumpvarsEntry> dumpvars() const
|
||||
VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
|
||||
// Internal: --prof-exec related settings
|
||||
uint64_t profExecStart() const VL_MT_SAFE { return m_ns.m_profExecStart; }
|
||||
void profExecStart(uint64_t flag) VL_MT_SAFE;
|
||||
|
||||
@@ -220,8 +220,9 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
const auto dumpvarsPath = Super::dumpvarsPath(m_prefixStack, name);
|
||||
|
||||
const bool enabled = Super::declCode(code, hierarchicalName, bits);
|
||||
const bool enabled = Super::declCode(code, dumpvarsPath, bits);
|
||||
if (!enabled) return;
|
||||
|
||||
assert(hierarchicalName.rfind(' ') != std::string::npos);
|
||||
|
||||
@@ -539,8 +539,9 @@ void VerilatedSaif::declare(const uint32_t code, uint32_t fidx, const char* name
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
const auto dumpvarsPath = Super::dumpvarsPath(m_prefixStack, name);
|
||||
|
||||
if (!Super::declCode(code, hierarchicalName, bits)) return;
|
||||
if (!Super::declCode(code, dumpvarsPath, bits)) return;
|
||||
|
||||
std::string variableName = lastWord(hierarchicalName);
|
||||
m_currentScope->addActivityVar(code, variableName);
|
||||
|
||||
@@ -313,7 +313,7 @@ private:
|
||||
uint32_t m_maxBits = 0; // Number of bits in the widest signal
|
||||
void* m_initUserp = nullptr; // The callback userp of the instance currently being initialized
|
||||
// TODO: Should keep this as a Trie, that is how it's accessed all the time.
|
||||
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
|
||||
std::vector<VerilatedTraceDumpvarsEntry> m_dumpvars; // dumpvar() entries
|
||||
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
||||
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
|
||||
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
||||
@@ -371,6 +371,59 @@ private:
|
||||
VL_UNCOPYABLE(VerilatedTrace);
|
||||
|
||||
protected:
|
||||
struct DumpvarsPath final {
|
||||
std::string m_name;
|
||||
std::vector<size_t> m_scopeEndps;
|
||||
|
||||
static bool countsAsScopeLevel(VerilatedTracePrefixType type) {
|
||||
return type == VerilatedTracePrefixType::SCOPE_MODULE
|
||||
|| type == VerilatedTracePrefixType::SCOPE_INTERFACE
|
||||
|| type == VerilatedTracePrefixType::ROOTIO_WRAPPER;
|
||||
}
|
||||
|
||||
static char separator(VerilatedTracePrefixType type) {
|
||||
return (type == VerilatedTracePrefixType::ARRAY_PACKED
|
||||
|| type == VerilatedTracePrefixType::ARRAY_UNPACKED)
|
||||
? '\0'
|
||||
: '.';
|
||||
}
|
||||
|
||||
static std::string trimPrefix(const std::string& prefix) {
|
||||
if (!prefix.empty() && prefix.back() == ' ') {
|
||||
return prefix.substr(0, prefix.size() - 1);
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
void append(const std::string& piece, VerilatedTracePrefixType type,
|
||||
bool countLevel = true) {
|
||||
if (piece.empty()) return;
|
||||
const char sep = separator(type);
|
||||
if (sep && !m_name.empty()) m_name += sep;
|
||||
m_name += piece;
|
||||
if (countLevel && countsAsScopeLevel(type)) m_scopeEndps.push_back(m_name.size());
|
||||
}
|
||||
|
||||
bool matchesPrefix(const std::string& prefix) const {
|
||||
if (prefix.empty()) return true;
|
||||
if (m_name.compare(0, prefix.size(), prefix) != 0) return false;
|
||||
return prefix.size() >= m_name.size() || m_name[prefix.size()] == '.';
|
||||
}
|
||||
|
||||
int scopeLevelsBelow(size_t prefixLen) const {
|
||||
int levels = 0;
|
||||
for (const size_t endp : m_scopeEndps) {
|
||||
if (endp > prefixLen) ++levels;
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
bool matches(const VerilatedTraceDumpvarsEntry& entry) const {
|
||||
if (!matchesPrefix(entry.m_hier)) return false;
|
||||
return entry.m_level <= 0 || scopeLevelsBelow(entry.m_hier.size()) < entry.m_level;
|
||||
}
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
@@ -390,7 +443,7 @@ protected:
|
||||
void traceInit() VL_MT_UNSAFE;
|
||||
|
||||
// Declare new signal and return true if enabled
|
||||
bool declCode(uint32_t code, const std::string& declName, uint32_t bits);
|
||||
bool declCode(uint32_t code, const DumpvarsPath& path, uint32_t bits);
|
||||
|
||||
void closeBase();
|
||||
void flushBase();
|
||||
@@ -405,6 +458,23 @@ protected:
|
||||
return str.substr(idx + 1);
|
||||
}
|
||||
|
||||
static DumpvarsPath dumpvarsPath(
|
||||
const std::vector<std::pair<std::string, VerilatedTracePrefixType>>& prefixStack,
|
||||
const char* namep) {
|
||||
DumpvarsPath out;
|
||||
std::string prev;
|
||||
for (size_t i = 1; i < prefixStack.size(); ++i) {
|
||||
const std::string curr = DumpvarsPath::trimPrefix(prefixStack[i].first);
|
||||
if (curr.size() < prev.size()) continue;
|
||||
std::string piece = curr.substr(prev.size());
|
||||
if (!piece.empty() && piece.front() == ' ') piece.erase(0, 1);
|
||||
out.append(piece, prefixStack[i].second);
|
||||
prev = curr;
|
||||
}
|
||||
out.append(namep ? namep : "", prefixStack.back().second, false);
|
||||
return out;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format-specific implementation
|
||||
|
||||
|
||||
@@ -369,7 +369,8 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
}
|
||||
|
||||
template <>
|
||||
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::string& declName,
|
||||
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code,
|
||||
const DumpvarsPath& path,
|
||||
uint32_t bits) {
|
||||
if (VL_UNCOVERABLE(!code)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
|
||||
@@ -377,21 +378,8 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::stri
|
||||
// To keep it simple, this is O(enables * signals), but we expect few enables
|
||||
bool enabled = false;
|
||||
if (m_dumpvars.empty()) enabled = true;
|
||||
for (const auto& item : m_dumpvars) {
|
||||
const int dumpvarsLevel = item.first;
|
||||
const char* dvp = item.second.c_str();
|
||||
const char* np = declName.c_str();
|
||||
while (*dvp && *dvp == *np) {
|
||||
++dvp;
|
||||
++np;
|
||||
}
|
||||
if (*dvp) continue; // Didn't match dumpvar item
|
||||
if (*np && *np != ' ') continue; // e.g. "t" isn't a match for "top"
|
||||
int levels = 0;
|
||||
while (*np) {
|
||||
if (*np++ == ' ') ++levels;
|
||||
}
|
||||
if (levels > dumpvarsLevel) continue; // Too deep
|
||||
for (const auto& entry : m_dumpvars) {
|
||||
if (!path.matches(entry)) continue;
|
||||
// We only need to set first code word if it's a multicode signal
|
||||
// as that's all we'll check for later
|
||||
if (m_sigs_enabledVec.size() <= code) m_sigs_enabledVec.resize((code + 1024) * 2);
|
||||
@@ -434,15 +422,10 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::set_time_resolution(const std::string&
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dumpvars(int level, const std::string& hier) VL_MT_SAFE {
|
||||
if (level == 0) {
|
||||
if (level == 0 && hier.empty()) {
|
||||
m_dumpvars.clear(); // empty = everything on
|
||||
} else {
|
||||
// Convert Verilog . separators to trace space separators
|
||||
std::string hierSpaced = hier;
|
||||
for (auto& i : hierSpaced) {
|
||||
if (i == '.') i = ' ';
|
||||
}
|
||||
m_dumpvars.emplace_back(level, hierSpaced);
|
||||
m_dumpvars.emplace_back(level, hier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -383,8 +383,9 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
const auto dumpvarsPath = Super::dumpvarsPath(m_prefixStack, name);
|
||||
|
||||
const bool enabled = Super::declCode(code, hierarchicalName, bits);
|
||||
const bool enabled = Super::declCode(code, dumpvarsPath, bits);
|
||||
|
||||
if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) {
|
||||
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
|
||||
|
||||
Reference in New Issue
Block a user