[#73220] add handling scopes to SAIF trace

This commit is contained in:
Mateusz Gancarz 2025-02-19 13:18:39 +01:00
parent 0e2cf72966
commit ab9ee43f8d
2 changed files with 102 additions and 15 deletions

View File

@ -229,19 +229,49 @@ void VerilatedSaif::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
printStr(std::to_string(m_time).c_str());
printStr(")\n");
incrementIndent();
printInstance(0);
decrementIndent();
printStr(")\n"); // SAIFILE
// This function is on the flush() call path
const VerilatedLockGuard lock{m_mutex};
if (!isOpen()) return;
closePrev();
// closePrev() called Super::flush(), so we just
// need to shut down the tracing thread here.
Super::closeBase();
}
void VerilatedSaif::printInstance(uint32_t scopeIndex) {
const SaifScope& saifScope = m_scopes.at(scopeIndex);
printIndent();
printStr("(INSTANCE ");
printStr(saifScope.scopeName.c_str());
printStr("\n");
//NOTE: for now only care about NET, also PORT will be added
printStr("(INSTANCE foo (NET\n");
for (auto& [code, activity] : m_activity) {
incrementIndent();
printIndent();
printStr("(NET\n");
incrementIndent();
for (auto& childSignalCode : saifScope.childSignalCodes) {
ActivityVar& activity = m_activity.at(childSignalCode);
for (size_t i = 0; i < activity.width; i++) {
auto& bit = activity.bits[i];
if (bit.lastVal && activity.lastTime < m_time) {
bit.highTime += m_time - activity.lastTime;
}
if (!bit.transitions) {
// Skip bits with no transitions
if (bit.transitions <= 0) {
// Skip bits with no transitions
continue;
}
assert(m_time >= bit.highTime);
printIndent();
printStr("(");
printStr(activity.name.c_str());
if (activity.width > 1) {
@ -262,15 +292,18 @@ void VerilatedSaif::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
}
activity.lastTime = m_time;
}
printStr("))"); // INSTANCE/NET
printStr(")\n"); // SAIFILE
// This function is on the flush() call path
const VerilatedLockGuard lock{m_mutex};
if (!isOpen()) return;
closePrev();
// closePrev() called Super::flush(), so we just
// need to shut down the tracing thread here.
Super::closeBase();
decrementIndent();
printIndent();
printStr(")\n"); // NET
for (uint32_t childScopeIndex : saifScope.childScopesIndices) {
printInstance(childScopeIndex);
}
decrementIndent();
printIndent();
printStr(")\n"); // INSTANCE
}
void VerilatedSaif::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
@ -331,10 +364,36 @@ void VerilatedSaif::bufferFlush() VL_MT_UNSAFE_ONE {
//=============================================================================
// Definitions
void VerilatedSaif::incrementIndent()
{
m_indent += 1;
}
void VerilatedSaif::decrementIndent()
{
m_indent -= 1;
}
void VerilatedSaif::printIndent() {
for (int i = 0; i < m_indent; ++i) printStr(" ");
}
void VerilatedSaif::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
fprintf(stdout, "Pushing prefix: %s\n", name.c_str());
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
std::string pname = name;
int32_t newScopeIndex = m_scopes.size();
m_scopes.emplace_back();
SaifScope& newScope = m_scopes.back();
newScope.scopeName = name;
if (m_currentScope >= 0) {
m_scopes.at(m_currentScope).childScopesIndices.emplace_back(newScopeIndex);
newScope.parentScopeIndex = m_currentScope;
}
m_currentScope = newScopeIndex;
// An empty name means this is the root of a model created with name()=="". The
// tools get upset if we try to pass this as empty, so we put the signals under a
// new scope, but the signals further down will be peers, not children (as usual
@ -376,6 +435,8 @@ void VerilatedSaif::popPrefix() {
fprintf(stdout, "Popping prefix: %s\n", m_prefixStack.back().first.c_str());
m_prefixStack.pop_back();
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
m_currentScope = m_scopes.at(m_currentScope).parentScopeIndex;
}
void VerilatedSaif::declare(uint32_t code, const char* name, const char* wirep, bool array,
@ -387,7 +448,7 @@ void VerilatedSaif::declare(uint32_t code, const char* name, const char* wirep,
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
const std::string hierarchicalName = m_prefixStack.back().first + name;
std::string hierarchicalName = m_prefixStack.back().first + name;
const bool enabled = Super::declCode(code, hierarchicalName, bits);
if (!enabled) return;
@ -407,6 +468,9 @@ void VerilatedSaif::declare(uint32_t code, const char* name, const char* wirep,
finalName += ']';
}
assert(m_currentScope >= 0);
m_scopes.at(m_currentScope).childSignalCodes.emplace_back(code);
m_activity.emplace(code, ActivityVar{
finalName,
static_cast<uint32_t>(lsb),
@ -427,6 +491,7 @@ void VerilatedSaif::declEvent(
void VerilatedSaif::printSignalDirection(VerilatedTraceSigDirection signalDirection)
{
return;
switch (signalDirection) {
case VerilatedTraceSigDirection::INPUT:
{
@ -453,6 +518,7 @@ void VerilatedSaif::printSignalDirection(VerilatedTraceSigDirection signalDirect
void VerilatedSaif::printSignalKind(VerilatedTraceSigKind signalKind)
{
return;
switch (signalKind) {
case VerilatedTraceSigKind::PARAMETER:
{
@ -498,6 +564,7 @@ void VerilatedSaif::printSignalKind(VerilatedTraceSigKind signalKind)
void VerilatedSaif::printSignalType(VerilatedTraceSigType signalType)
{
return;
switch (signalType) {
case VerilatedTraceSigType::DOUBLE:
{
@ -700,7 +767,7 @@ void VerilatedSaifBuffer::emitQData(uint32_t code, QData newval, int bits) {
if (bits > activity.width) {
fprintf(stdout, "Trying to emit more bits than activity width\n");
}
auto dt = m_owner.m_time - activity.lastTime;
for (size_t i = 0; i < activity.width; i++) {
activity.bits[i].aggregateVal(dt, (newval >> i) & 1);

View File

@ -30,6 +30,7 @@
class VerilatedSaifBuffer;
class VerilatedSaifFile;
struct ActivityBit {
bool lastVal = false;
uint64_t highTime = 0;
@ -42,6 +43,7 @@ struct ActivityBit {
lastVal = newVal;
}
};
struct ActivityVar {
std::string name;
uint32_t lsb;
@ -50,6 +52,13 @@ struct ActivityVar {
uint64_t lastTime = 0;
};
struct SaifScope {
std::string scopeName{};
std::vector<int32_t> childScopesIndices{};
std::vector<uint32_t> childSignalCodes{};
int32_t parentScopeIndex{-1};
};
//=============================================================================
// VerilatedSaif
// Base class to create a Verilator SAIF dump
@ -70,6 +79,11 @@ private:
bool m_isOpen = false; // True indicates open file
std::string m_filename; // Filename we're writing to (if open)
uint64_t m_rolloverSize = 0; // File size to rollover at
void incrementIndent();
void decrementIndent();
void printIndent();
int m_indent = 0; // Indentation depth
char* m_wrBufp; // Output buffer
@ -79,6 +93,10 @@ private:
size_t m_maxSignalBytes = 0; // Upper bound on number of bytes a single signal can generate
uint64_t m_wroteBytes = 0; // Number of bytes written to this file
std::vector<SaifScope> m_scopes{};
std::vector<uint32_t> m_topScopes{};
int32_t m_currentScope{-1};
std::unordered_map<uint32_t, ActivityVar> m_activity;
std::vector<std::vector<ActivityBit>> m_activityArena;
uint64_t m_time;
@ -105,6 +123,8 @@ private:
void declare(uint32_t code, const char* name, const char* wirep, bool array, int arraynum,
bool bussed, int msb, int lsb);
void printInstance(uint32_t scopeIndex);
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedSaif);