Compare commits
8 Commits
b383f64cff
...
93cc24b2f9
| Author | SHA1 | Date |
|---|---|---|
|
|
93cc24b2f9 | |
|
|
de25b70596 | |
|
|
5a72dda1f3 | |
|
|
38e483440e | |
|
|
4027cdebc2 | |
|
|
bdb7050411 | |
|
|
e296d90328 | |
|
|
c71f5b42e3 |
|
|
@ -59,6 +59,162 @@
|
|||
#undef VL_SUB_T
|
||||
#undef VL_BUF_T
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityBit
|
||||
|
||||
class VerilatedSaifActivityBit final {
|
||||
// MEMBERS
|
||||
bool m_lastVal = false; // last emitted activity bit value
|
||||
uint64_t m_highTime = 0; // total time when bit was high
|
||||
size_t m_transitions = 0; // total number of bit transitions
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE
|
||||
void aggregateVal(uint64_t dt, bool newVal) {
|
||||
m_transitions += newVal != m_lastVal ? 1 : 0;
|
||||
m_highTime += m_lastVal ? dt : 0;
|
||||
m_lastVal = newVal;
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE bool bitValue() const { return m_lastVal; }
|
||||
VL_ATTR_ALWINLINE uint64_t highTime() const { return m_highTime; }
|
||||
VL_ATTR_ALWINLINE uint64_t toggleCount() const { return m_transitions; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityVar
|
||||
|
||||
class VerilatedSaifActivityVar final {
|
||||
// MEMBERS
|
||||
uint64_t m_lastTime{0}; // last time when variable value was updated
|
||||
VerilatedSaifActivityBit* m_bits; // pointer to variable bits objects
|
||||
uint32_t m_width; // width of variable (in bits)
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSaifActivityVar(uint32_t width, VerilatedSaifActivityBit* bits)
|
||||
: m_bits{bits}
|
||||
, m_width{width} {}
|
||||
|
||||
VerilatedSaifActivityVar(VerilatedSaifActivityVar&&) = default;
|
||||
VerilatedSaifActivityVar& operator=(VerilatedSaifActivityVar&&) = default;
|
||||
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE void emitBit(uint64_t time, CData newval);
|
||||
|
||||
template <typename DataType>
|
||||
VL_ATTR_ALWINLINE void emitData(uint64_t time, DataType newval, uint32_t bits) {
|
||||
static_assert(std::is_integral<DataType>::value,
|
||||
"The emitted value must be of integral type");
|
||||
|
||||
const uint64_t dt = time - m_lastTime;
|
||||
for (size_t i = 0; i < std::min(m_width, bits); i++) {
|
||||
m_bits[i].aggregateVal(dt, (newval >> i) & 1);
|
||||
}
|
||||
updateLastTime(time);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE void emitWData(uint64_t time, const WData* newvalp, uint32_t bits);
|
||||
VL_ATTR_ALWINLINE void updateLastTime(uint64_t val) { m_lastTime = val; }
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE uint32_t width() const { return m_width; }
|
||||
VL_ATTR_ALWINLINE VerilatedSaifActivityBit& bit(std::size_t index);
|
||||
VL_ATTR_ALWINLINE uint64_t lastUpdateTime() const { return m_lastTime; }
|
||||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSaifActivityVar);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityScope
|
||||
|
||||
class VerilatedSaifActivityScope final {
|
||||
// MEMBERS
|
||||
// absolute path to the scope
|
||||
std::string m_scopePath{};
|
||||
// name of the activity scope
|
||||
std::string m_scopeName{};
|
||||
// array indices of child scopes
|
||||
std::vector<std::unique_ptr<VerilatedSaifActivityScope>> m_childScopes{};
|
||||
// children signals codes mapped to their names in the current scope
|
||||
std::vector<std::pair<uint32_t, std::string>> m_childActivities{};
|
||||
// parent scope pointer
|
||||
VerilatedSaifActivityScope* m_parentScope{nullptr};
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSaifActivityScope(std::string scopePath, std::string name,
|
||||
VerilatedSaifActivityScope* parentScope = nullptr)
|
||||
: m_scopePath{std::move(scopePath)}
|
||||
, m_scopeName{std::move(name)}
|
||||
, m_parentScope{parentScope} {}
|
||||
|
||||
VerilatedSaifActivityScope(VerilatedSaifActivityScope&&) = default;
|
||||
VerilatedSaifActivityScope& operator=(VerilatedSaifActivityScope&&) = default;
|
||||
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE void addChildScope(std::unique_ptr<VerilatedSaifActivityScope> childScope) {
|
||||
m_childScopes.emplace_back(std::move(childScope));
|
||||
}
|
||||
VL_ATTR_ALWINLINE void addActivityVar(uint32_t code, std::string name) {
|
||||
m_childActivities.emplace_back(code, std::move(name));
|
||||
}
|
||||
VL_ATTR_ALWINLINE bool hasParent() const { return m_parentScope; }
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE const std::string& path() const { return m_scopePath; }
|
||||
VL_ATTR_ALWINLINE const std::string& name() const { return m_scopeName; }
|
||||
VL_ATTR_ALWINLINE const std::vector<std::unique_ptr<VerilatedSaifActivityScope>>&
|
||||
childScopes() const {
|
||||
return m_childScopes;
|
||||
}
|
||||
VL_ATTR_ALWINLINE
|
||||
const std::vector<std::pair<uint32_t, std::string>>& childActivities() const {
|
||||
return m_childActivities;
|
||||
}
|
||||
VL_ATTR_ALWINLINE VerilatedSaifActivityScope* parentScope() const { return m_parentScope; }
|
||||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSaifActivityScope);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityAccumulator
|
||||
|
||||
class VerilatedSaifActivityAccumulator final {
|
||||
// Give access to the private activities
|
||||
friend class VerilatedSaifBuffer;
|
||||
friend class VerilatedSaif;
|
||||
|
||||
// MEMBERS
|
||||
// map of scopes paths to codes of activities inside
|
||||
std::unordered_map<std::string, std::vector<std::pair<uint32_t, std::string>>>
|
||||
m_scopeToActivities;
|
||||
// map of variables codes mapped to their activity objects
|
||||
std::unordered_map<uint32_t, VerilatedSaifActivityVar> m_activity;
|
||||
// memory pool for signals bits objects
|
||||
std::vector<std::vector<VerilatedSaifActivityBit>> m_activityArena;
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
void declare(uint32_t code, const std::string& absoluteScopePath, std::string variableName,
|
||||
int bits, bool array, int arraynum);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedSaifActivityAccumulator() = default;
|
||||
|
||||
VerilatedSaifActivityAccumulator(VerilatedSaifActivityAccumulator&&) = default;
|
||||
VerilatedSaifActivityAccumulator& operator=(VerilatedSaifActivityAccumulator&&) = default;
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedSaifActivityAccumulator);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
|
|
@ -94,7 +250,9 @@ VerilatedSaifActivityBit& VerilatedSaifActivityVar::bit(const std::size_t index)
|
|||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
VerilatedSaif::VerilatedSaif(void* filep) {}
|
||||
VerilatedSaif::VerilatedSaif(void* filep) {
|
||||
m_activityAccumulators.emplace_back(std::make_unique<VerilatedSaifActivityAccumulator>());
|
||||
}
|
||||
|
||||
void VerilatedSaif::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
|
|
@ -146,20 +304,16 @@ void VerilatedSaif::finalizeSaifFileContents() {
|
|||
printStr(")\n");
|
||||
|
||||
incrementIndent();
|
||||
for (const int32_t topScopeIndex : m_topScopes) recursivelyPrintScopes(topScopeIndex);
|
||||
for (const auto& topScope : m_scopes) recursivelyPrintScopes(*topScope);
|
||||
decrementIndent();
|
||||
|
||||
printStr(")\n"); // SAIFILE
|
||||
}
|
||||
|
||||
void VerilatedSaif::recursivelyPrintScopes(const uint32_t scopeIndex) {
|
||||
const VerilatedSaifActivityScope& scope = m_scopes.at(scopeIndex);
|
||||
|
||||
void VerilatedSaif::recursivelyPrintScopes(const VerilatedSaifActivityScope& scope) {
|
||||
openInstanceScope(scope.name());
|
||||
printScopeActivities(scope);
|
||||
for (uint32_t childScopeIndex : scope.childScopesIndices()) {
|
||||
recursivelyPrintScopes(childScopeIndex);
|
||||
}
|
||||
for (const auto& childScope : scope.childScopes()) { recursivelyPrintScopes(*childScope); }
|
||||
closeInstanceScope();
|
||||
}
|
||||
|
||||
|
|
@ -178,14 +332,28 @@ void VerilatedSaif::closeInstanceScope() {
|
|||
}
|
||||
|
||||
void VerilatedSaif::printScopeActivities(const VerilatedSaifActivityScope& scope) {
|
||||
bool anyNetValid{false};
|
||||
for (const auto& childSignal : scope.childActivities()) {
|
||||
const uint32_t code = childSignal.first;
|
||||
const char* const name = childSignal.second.c_str();
|
||||
anyNetValid = printActivityStats(code, name, anyNetValid);
|
||||
bool anyNetWritten{false};
|
||||
|
||||
for (auto& accumulator : m_activityAccumulators) {
|
||||
anyNetWritten |= printScopeActivitiesFromAccumulatorIfPresent(scope.path(), *accumulator,
|
||||
anyNetWritten);
|
||||
}
|
||||
|
||||
if (anyNetValid) closeNetScope();
|
||||
if (anyNetWritten) closeNetScope();
|
||||
}
|
||||
|
||||
bool VerilatedSaif::printScopeActivitiesFromAccumulatorIfPresent(
|
||||
const std::string& absoluteScopePath, VerilatedSaifActivityAccumulator& accumulator,
|
||||
bool anyNetWritten) {
|
||||
if (accumulator.m_scopeToActivities.count(absoluteScopePath) == 0) return false;
|
||||
|
||||
for (const auto& childSignal : accumulator.m_scopeToActivities.at(absoluteScopePath)) {
|
||||
VerilatedSaifActivityVar& activityVariable = accumulator.m_activity.at(childSignal.first);
|
||||
anyNetWritten
|
||||
= printActivityStats(activityVariable, childSignal.second.c_str(), anyNetWritten);
|
||||
}
|
||||
|
||||
return anyNetWritten;
|
||||
}
|
||||
|
||||
void VerilatedSaif::openNetScope() {
|
||||
|
|
@ -200,9 +368,8 @@ void VerilatedSaif::closeNetScope() {
|
|||
printStr(")\n");
|
||||
}
|
||||
|
||||
bool VerilatedSaif::printActivityStats(const uint32_t activityCode, const char* activityName,
|
||||
bool anyNetValid) {
|
||||
VerilatedSaifActivityVar& activity = m_activity.at(activityCode);
|
||||
bool VerilatedSaif::printActivityStats(VerilatedSaifActivityVar& activity,
|
||||
const char* activityName, bool anyNetWritten) {
|
||||
for (size_t i = 0; i < activity.width(); ++i) {
|
||||
VerilatedSaifActivityBit& bit = activity.bit(i);
|
||||
|
||||
|
|
@ -213,9 +380,9 @@ bool VerilatedSaif::printActivityStats(const uint32_t activityCode, const char*
|
|||
|
||||
bit.aggregateVal(currentTime() - activity.lastUpdateTime(), bit.bitValue());
|
||||
|
||||
if (!anyNetValid) {
|
||||
if (!anyNetWritten) {
|
||||
openNetScope();
|
||||
anyNetValid = true;
|
||||
anyNetWritten = true;
|
||||
}
|
||||
|
||||
printIndent();
|
||||
|
|
@ -239,15 +406,13 @@ bool VerilatedSaif::printActivityStats(const uint32_t activityCode, const char*
|
|||
|
||||
activity.updateLastTime(currentTime());
|
||||
|
||||
return anyNetValid;
|
||||
return anyNetWritten;
|
||||
}
|
||||
|
||||
void VerilatedSaif::clearCurrentlyCollectedData() {
|
||||
m_currentScope = -1;
|
||||
m_currentScope = nullptr;
|
||||
m_scopes.clear();
|
||||
m_topScopes.clear();
|
||||
m_activity.clear();
|
||||
m_activityArena.clear();
|
||||
m_activityAccumulators.clear();
|
||||
}
|
||||
|
||||
void VerilatedSaif::printStr(const char* str) { ::write(m_filep, str, strlen(str)); }
|
||||
|
|
@ -281,14 +446,21 @@ void VerilatedSaif::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||
|
||||
if (type != VerilatedTracePrefixType::ARRAY_UNPACKED
|
||||
&& type != VerilatedTracePrefixType::ARRAY_PACKED) {
|
||||
const int32_t newScopeIndex = m_scopes.size();
|
||||
if (m_currentScope >= 0) {
|
||||
m_scopes.at(m_currentScope).addChildScopeIndex(newScopeIndex);
|
||||
|
||||
std::string scopePath = m_prefixStack.back().first + pname;
|
||||
std::string scopeName = lastWord(scopePath);
|
||||
|
||||
auto newScope = std::make_unique<VerilatedSaifActivityScope>(
|
||||
std::move(scopePath), std::move(scopeName), m_currentScope);
|
||||
VerilatedSaifActivityScope* newScopePtr = newScope.get();
|
||||
|
||||
if (m_currentScope) {
|
||||
m_currentScope->addChildScope(std::move(newScope));
|
||||
} else {
|
||||
m_topScopes.emplace_back(newScopeIndex);
|
||||
m_scopes.emplace_back(std::move(newScope));
|
||||
}
|
||||
m_scopes.emplace_back(lastWord(m_prefixStack.back().first + pname), m_currentScope);
|
||||
m_currentScope = newScopeIndex;
|
||||
|
||||
m_currentScope = newScopePtr;
|
||||
}
|
||||
|
||||
std::string newPrefix = m_prefixStack.back().first + pname;
|
||||
|
|
@ -303,22 +475,16 @@ void VerilatedSaif::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||
void VerilatedSaif::popPrefix() {
|
||||
if (m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_UNPACKED
|
||||
&& m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_PACKED
|
||||
&& m_currentScope >= 0) {
|
||||
m_currentScope = m_scopes.at(m_currentScope).parentScopeIndex();
|
||||
&& m_currentScope != nullptr) {
|
||||
m_currentScope = m_currentScope->parentScope();
|
||||
}
|
||||
|
||||
m_prefixStack.pop_back();
|
||||
}
|
||||
|
||||
void VerilatedSaif::declare(const uint32_t code, const char* name, const char* wirep,
|
||||
const bool array, const int arraynum, const bool bussed, const int msb,
|
||||
const int lsb) {
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
|
||||
if (!Super::declCode(code, hierarchicalName, bits)) return;
|
||||
|
||||
void VerilatedSaifActivityAccumulator::declare(uint32_t code, const std::string& absoluteScopePath,
|
||||
std::string variableName, int bits, bool array,
|
||||
int arraynum) {
|
||||
const size_t block_size = 1024;
|
||||
if (m_activityArena.empty()
|
||||
|| m_activityArena.back().size() + bits > m_activityArena.back().capacity()) {
|
||||
|
|
@ -328,56 +494,71 @@ void VerilatedSaif::declare(const uint32_t code, const char* name, const char* w
|
|||
const size_t bitsIdx = m_activityArena.back().size();
|
||||
m_activityArena.back().resize(m_activityArena.back().size() + bits);
|
||||
|
||||
std::string finalName = lastWord(hierarchicalName);
|
||||
if (array) {
|
||||
finalName += '[';
|
||||
finalName += std::to_string(arraynum);
|
||||
finalName += ']';
|
||||
variableName += '[';
|
||||
variableName += std::to_string(arraynum);
|
||||
variableName += ']';
|
||||
}
|
||||
|
||||
assert(m_currentScope >= 0);
|
||||
m_scopes.at(m_currentScope).addActivityVar(code, std::move(finalName));
|
||||
|
||||
m_scopeToActivities[absoluteScopePath].emplace_back(code, variableName);
|
||||
m_activity.emplace(code, VerilatedSaifActivityVar{static_cast<uint32_t>(bits),
|
||||
m_activityArena.back().data() + bitsIdx});
|
||||
}
|
||||
|
||||
void VerilatedSaif::declare(const uint32_t code, uint32_t fidx, const char* name,
|
||||
const char* wirep, const bool array, const int arraynum,
|
||||
const bool bussed, const int msb, const int lsb) {
|
||||
assert(m_activityAccumulators.size() > fidx);
|
||||
VerilatedSaifActivityAccumulator& accumulator = *m_activityAccumulators.at(fidx);
|
||||
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
|
||||
if (!Super::declCode(code, hierarchicalName, bits)) return;
|
||||
|
||||
std::string variableName = lastWord(hierarchicalName);
|
||||
m_currentScope->addActivityVar(code, variableName);
|
||||
|
||||
accumulator.declare(code, m_currentScope->path(), std::move(variableName), bits, array,
|
||||
arraynum);
|
||||
}
|
||||
|
||||
void VerilatedSaif::declEvent(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum) {
|
||||
declare(code, name, "event", array, arraynum, false, 0, 0);
|
||||
declare(code, fidx, name, "event", array, arraynum, false, 0, 0);
|
||||
}
|
||||
|
||||
void VerilatedSaif::declBit(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum) {
|
||||
declare(code, name, "wire", array, arraynum, false, 0, 0);
|
||||
declare(code, fidx, name, "wire", array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedSaif::declBus(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum, const int msb, const int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedSaif::declQuad(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum, const int msb, const int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedSaif::declArray(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum, const int msb, const int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
declare(code, fidx, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedSaif::declDouble(const uint32_t code, const uint32_t fidx, const char* name,
|
||||
const int dtypenum, const VerilatedTraceSigDirection,
|
||||
const VerilatedTraceSigKind, const VerilatedTraceSigType,
|
||||
const bool array, const int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, 63, 0);
|
||||
declare(code, fidx, name, "real", array, arraynum, false, 63, 0);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
|
@ -404,43 +585,55 @@ void VerilatedSaifBuffer::emitEvent(const uint32_t code) {
|
|||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitBit(const uint32_t code, const CData newval) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitBit(m_owner.currentTime(), newval);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitCData(const uint32_t code, const CData newval, const int bits) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitData<CData>(m_owner.currentTime(), newval, bits);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitSData(const uint32_t code, const SData newval, const int bits) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitData<SData>(m_owner.currentTime(), newval, bits);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitIData(const uint32_t code, const IData newval, const int bits) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitData<IData>(m_owner.currentTime(), newval, bits);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitQData(const uint32_t code, const QData newval, const int bits) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitData<QData>(m_owner.currentTime(), newval, bits);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitWData(const uint32_t code, const WData* newvalp, const int bits) {
|
||||
assert(m_owner.m_activity.count(code) && "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity = m_owner.m_activity.at(code);
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitWData(m_owner.currentTime(), newvalp, bits);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,122 +29,10 @@
|
|||
#include <vector>
|
||||
|
||||
class VerilatedSaifBuffer;
|
||||
class VerilatedSaifFile;
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityBit
|
||||
|
||||
class VerilatedSaifActivityBit final {
|
||||
// MEMBERS
|
||||
bool m_lastVal = false; // last emitted activity bit value
|
||||
uint64_t m_highTime = 0; // total time when bit was high
|
||||
size_t m_transitions = 0; // total number of bit transitions
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE
|
||||
void aggregateVal(uint64_t dt, bool newVal) {
|
||||
m_transitions += newVal != m_lastVal ? 1 : 0;
|
||||
m_highTime += m_lastVal ? dt : 0;
|
||||
m_lastVal = newVal;
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE bool bitValue() const { return m_lastVal; }
|
||||
VL_ATTR_ALWINLINE uint64_t highTime() const { return m_highTime; }
|
||||
VL_ATTR_ALWINLINE uint64_t toggleCount() const { return m_transitions; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityVar
|
||||
|
||||
class VerilatedSaifActivityVar final {
|
||||
// MEMBERS
|
||||
uint64_t m_lastTime{0}; // last time when variable value was updated
|
||||
VerilatedSaifActivityBit* m_bits; // pointer to variable bits objects
|
||||
uint32_t m_width; // width of variable (in bits)
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSaifActivityVar(uint32_t width, VerilatedSaifActivityBit* bits)
|
||||
: m_bits{bits}
|
||||
, m_width{width} {}
|
||||
|
||||
VerilatedSaifActivityVar(VerilatedSaifActivityVar&&) = default;
|
||||
VerilatedSaifActivityVar& operator=(VerilatedSaifActivityVar&&) = default;
|
||||
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE void emitBit(uint64_t time, CData newval);
|
||||
|
||||
template <typename DataType>
|
||||
VL_ATTR_ALWINLINE void emitData(uint64_t time, DataType newval, uint32_t bits) {
|
||||
static_assert(std::is_integral<DataType>::value,
|
||||
"The emitted value must be of integral type");
|
||||
|
||||
const uint64_t dt = time - m_lastTime;
|
||||
for (size_t i = 0; i < std::min(m_width, bits); i++) {
|
||||
m_bits[i].aggregateVal(dt, (newval >> i) & 1);
|
||||
}
|
||||
updateLastTime(time);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE void emitWData(uint64_t time, const WData* newvalp, uint32_t bits);
|
||||
VL_ATTR_ALWINLINE void updateLastTime(uint64_t val) { m_lastTime = val; }
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE uint32_t width() const { return m_width; }
|
||||
VL_ATTR_ALWINLINE VerilatedSaifActivityBit& bit(std::size_t index);
|
||||
VL_ATTR_ALWINLINE uint64_t lastUpdateTime() const { return m_lastTime; }
|
||||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSaifActivityVar);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaifActivityScope
|
||||
|
||||
class VerilatedSaifActivityScope final {
|
||||
// MEMBERS
|
||||
std::string m_scopeName{}; // name of the activity scope
|
||||
std::vector<int32_t> m_childScopesIndices{}; // array indices of child scopes
|
||||
std::vector<std::pair<uint32_t, std::string>>
|
||||
m_childActivities{}; // children signals codes mapped to their names in the current scope
|
||||
int32_t m_parentScopeIndex{-1}; // array index of parent scope
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSaifActivityScope(std::string name, int32_t parentScopeIndex = -1)
|
||||
: m_scopeName{std::move(name)}
|
||||
, m_parentScopeIndex{parentScopeIndex} {}
|
||||
|
||||
VerilatedSaifActivityScope(VerilatedSaifActivityScope&&) = default;
|
||||
VerilatedSaifActivityScope& operator=(VerilatedSaifActivityScope&&) = default;
|
||||
|
||||
// METHODS
|
||||
VL_ATTR_ALWINLINE void addChildScopeIndex(int32_t index) {
|
||||
m_childScopesIndices.emplace_back(index);
|
||||
}
|
||||
VL_ATTR_ALWINLINE void addActivityVar(uint32_t code, std::string name) {
|
||||
m_childActivities.emplace_back(code, std::move(name));
|
||||
}
|
||||
VL_ATTR_ALWINLINE bool hasParent() const { return m_parentScopeIndex >= 0; }
|
||||
|
||||
// ACCESSORS
|
||||
VL_ATTR_ALWINLINE const std::string& name() const { return m_scopeName; }
|
||||
VL_ATTR_ALWINLINE const std::vector<int32_t>& childScopesIndices() const {
|
||||
return m_childScopesIndices;
|
||||
}
|
||||
VL_ATTR_ALWINLINE
|
||||
const std::vector<std::pair<uint32_t, std::string>>& childActivities() const {
|
||||
return m_childActivities;
|
||||
}
|
||||
VL_ATTR_ALWINLINE int32_t parentScopeIndex() const { return m_parentScopeIndex; }
|
||||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSaifActivityScope);
|
||||
};
|
||||
class VerilatedSaifActivityAccumulator;
|
||||
class VerilatedSaifActivityScope;
|
||||
class VerilatedSaifActivityVar;
|
||||
class VerilatedSaifActivityBit;
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSaif
|
||||
|
|
@ -167,16 +55,14 @@ private:
|
|||
|
||||
int m_indent = 0; // indentation size in spaces
|
||||
|
||||
int32_t m_currentScope{-1}; // currently active scope
|
||||
std::vector<VerilatedSaifActivityScope> m_scopes{}; // array of declared scopes
|
||||
std::vector<int32_t> m_topScopes{}; // array of top scopes
|
||||
|
||||
std::unordered_map<uint32_t, VerilatedSaifActivityVar>
|
||||
m_activity; // map of variables codes mapped to their activity objects
|
||||
std::vector<std::vector<VerilatedSaifActivityBit>>
|
||||
m_activityArena; // memory pool for signals bits objects
|
||||
|
||||
uint64_t m_time{0}; // total time of the currently traced simulation
|
||||
// currently active scope
|
||||
VerilatedSaifActivityScope* m_currentScope{nullptr};
|
||||
// array of declared scopes
|
||||
std::vector<std::unique_ptr<VerilatedSaifActivityScope>> m_scopes{};
|
||||
// activity accumulators used to store variables statistics over simulation time
|
||||
std::vector<std::unique_ptr<VerilatedSaifActivityAccumulator>> m_activityAccumulators{};
|
||||
// total time of the currently traced simulation
|
||||
uint64_t m_time{0};
|
||||
|
||||
// stack of declared scopes combined names
|
||||
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
|
||||
|
|
@ -187,13 +73,18 @@ private:
|
|||
|
||||
void initializeSaifFileContents();
|
||||
void finalizeSaifFileContents();
|
||||
void recursivelyPrintScopes(uint32_t scopeIndex);
|
||||
void recursivelyPrintScopes(const VerilatedSaifActivityScope& scope);
|
||||
void openInstanceScope(const std::string& instanceName);
|
||||
void closeInstanceScope();
|
||||
void printScopeActivities(const VerilatedSaifActivityScope& scope);
|
||||
bool
|
||||
printScopeActivitiesFromAccumulatorIfPresent(const std::string& absoluteScopePath,
|
||||
VerilatedSaifActivityAccumulator& accumulator,
|
||||
bool anyNetWritten);
|
||||
void openNetScope();
|
||||
void closeNetScope();
|
||||
bool printActivityStats(uint32_t activityCode, const char* activityName, bool anyNetValid);
|
||||
bool printActivityStats(VerilatedSaifActivityVar& activity, const char* activityName,
|
||||
bool anyNetWritten);
|
||||
|
||||
void incrementIndent();
|
||||
void decrementIndent();
|
||||
|
|
@ -204,8 +95,8 @@ private:
|
|||
|
||||
void clearCurrentlyCollectedData();
|
||||
|
||||
void declare(uint32_t code, const char* name, const char* wirep, bool array, int arraynum,
|
||||
bool bussed, int msb, int lsb);
|
||||
void declare(uint32_t code, uint32_t fidx, const char* name, const char* wirep, bool array,
|
||||
int arraynum, bool bussed, int msb, int lsb);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSaif);
|
||||
|
|
@ -236,11 +127,6 @@ public:
|
|||
explicit VerilatedSaif(void* filep = nullptr);
|
||||
~VerilatedSaif();
|
||||
|
||||
// ACCESSORS
|
||||
// Set size in bytes after which new file should be created.
|
||||
void rolloverSize(uint64_t size) VL_MT_SAFE { /* noop */
|
||||
}
|
||||
|
||||
// METHODS - All must be thread safe
|
||||
// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
|
|
@ -304,10 +190,15 @@ class VerilatedSaifBuffer VL_NOT_FINAL {
|
|||
friend VerilatedSaif::OffloadBuffer;
|
||||
|
||||
VerilatedSaif& m_owner; // Trace file owning this buffer. Required by subclasses.
|
||||
uint32_t m_fidx; // Index of target activity accumulator
|
||||
|
||||
// CONSTRUCTOR
|
||||
// CONSTRUCTORS
|
||||
explicit VerilatedSaifBuffer(VerilatedSaif& owner)
|
||||
: m_owner{owner} {}
|
||||
: m_owner{owner}
|
||||
, m_fidx{0} {}
|
||||
explicit VerilatedSaifBuffer(VerilatedSaif& owner, uint32_t fidx)
|
||||
: m_owner{owner}
|
||||
, m_fidx{fidx} {}
|
||||
virtual ~VerilatedSaifBuffer() = default;
|
||||
|
||||
//=========================================================================
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0115,C0116,C0209,C0302,R0902,R0903,R0904,R0912,R0913,R0914,R0915,R0916,W0212,W0511,W0603,W1201
|
||||
# pylint: disable=C0114,C0115,C0116,R0902,R0903,R0912,R0915,W0719,W0718
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import re
|
||||
|
||||
SUCCESS_CODE = 0
|
||||
FAILURE_CODE = 1
|
||||
|
||||
INSTANCE_TYPE = "INSTANCE"
|
||||
NET_LIST_TYPE = "NET"
|
||||
SIGNAL_TYPE = "SIGNAL"
|
||||
|
||||
EOF_ERROR = "Unexpected EOF"
|
||||
|
||||
|
||||
def saif_assert(expression, message):
|
||||
if not expression:
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
def saif_error(message):
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
class SAIFSignalBit:
|
||||
name: str
|
||||
high_time: int
|
||||
|
|
@ -55,12 +55,9 @@ class SAIFParser:
|
|||
|
||||
def __init__(self):
|
||||
self.token_stack = []
|
||||
|
||||
# for parsing simplicity
|
||||
self.token_stack.append(SAIFToken('saif_root'))
|
||||
|
||||
self.current_instance = None
|
||||
|
||||
self.has_saifile_header = False
|
||||
self.direction = ''
|
||||
self.saif_version = ''
|
||||
|
|
@ -71,144 +68,107 @@ class SAIFParser:
|
|||
|
||||
def parse(self, saif_filename):
|
||||
file_contents = ''
|
||||
|
||||
with open(saif_filename, 'r', encoding="utf8") as saif_file:
|
||||
content = saif_file.readlines()
|
||||
filtered_lines = [line for line in content if not line.strip().startswith('//')]
|
||||
file_contents = ''.join(filtered_lines)
|
||||
|
||||
tokens = file_contents.replace('(', ' ( ').replace(')', ' ) ').split()
|
||||
num_of_tokens = len(tokens)
|
||||
|
||||
index = 0
|
||||
while index < num_of_tokens:
|
||||
token = tokens[index]
|
||||
index += 1
|
||||
|
||||
if token == '(':
|
||||
self.token_stack.append(SAIFToken(token))
|
||||
self.token_stack[-1].type = self.token_stack[-2].type
|
||||
self.token_stack[-1].value = self.token_stack[-2].value
|
||||
|
||||
continue
|
||||
|
||||
if token == ')':
|
||||
if self.token_stack[-1].type == INSTANCE_TYPE:
|
||||
self.current_instance = self.current_instance.parent_instance
|
||||
|
||||
self.token_stack.pop()
|
||||
continue
|
||||
|
||||
if re.match(r'SAIFILE', token):
|
||||
self.has_saifile_header = True
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DIRECTION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.direction = tokens[index].replace('\"', '')
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'SAIFVERSION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.saif_version = tokens[index].replace('\"', '')
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DESIGN|DATE|VENDOR|PROGRAM_NAME|VERSION', token):
|
||||
# noop, only skip value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DIVIDER', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.divider = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TIMESCALE', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.timescale = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DURATION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.duration = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'INSTANCE', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
instance_name = tokens[index]
|
||||
index += 1
|
||||
|
||||
self.token_stack[-1].type = INSTANCE_TYPE
|
||||
self.token_stack[-1].value = instance_name
|
||||
|
||||
instance = SAIFInstance(instance_name)
|
||||
|
||||
if self.current_instance is None:
|
||||
self.top_instances[instance_name] = instance
|
||||
else:
|
||||
self.current_instance.child_instances[instance_name] = instance
|
||||
|
||||
instance.parent_instance = self.current_instance
|
||||
self.current_instance = instance
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'NET', token):
|
||||
self.token_stack[-1].type = NET_LIST_TYPE
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'T1', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].high_time = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'T0', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].low_time = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TC', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].transitions = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TZ|TX|TB|TG|IG|IK', token):
|
||||
# noop, only skip value
|
||||
index += 1
|
||||
continue
|
||||
|
||||
if self.token_stack[-2].type == NET_LIST_TYPE:
|
||||
self.token_stack[-1].type = SIGNAL_TYPE
|
||||
self.token_stack[-1].value = token
|
||||
self.current_instance.nets[token] = (SAIFSignalBit(token))
|
||||
|
||||
self.current_instance.nets[token] = SAIFSignalBit(token)
|
||||
saif_assert(self.has_saifile_header, "SAIF file doesn't contain a SAIFILE keyword")
|
||||
saif_assert(self.direction == "backward", f"SAIF file doesn't have a valid/compatible direction: {self.direction}")
|
||||
saif_assert(self.saif_version == "2.0", f"SAIF file doesn't have a valid/compatible version: {self.saif_version}")
|
||||
|
||||
saif_assert(self.direction == "backward",
|
||||
f"SAIF file doesn't have a valid/compatible direction: {self.direction}")
|
||||
saif_assert(self.saif_version == "2.0",
|
||||
f"SAIF file doesn't have a valid/compatible version: {self.saif_version}")
|
||||
# only 'saif_root' token should be left
|
||||
saif_assert(len(self.token_stack) == 1, "Incorrect nesting of scopes")
|
||||
|
||||
|
|
@ -216,78 +176,58 @@ class SAIFParser:
|
|||
def compare_saif_instances(first: SAIFInstance, second: SAIFInstance):
|
||||
if len(first.nets) != len(second.nets):
|
||||
saif_error(f"Number of nets doesn't match in {first.scope_name}: "
|
||||
f"{len(first.nets)} != {len(second.nets)}")
|
||||
|
||||
f"{len(first.nets)} != {len(second.nets)}")
|
||||
for signal_name, saif_signal in first.nets.items():
|
||||
if signal_name not in second.nets:
|
||||
saif_error(f"Signal {signal_name} doesn't exist in the second object\n")
|
||||
|
||||
other_signal = second.nets[signal_name]
|
||||
|
||||
if (saif_signal.high_time != other_signal.high_time
|
||||
or saif_signal.low_time != other_signal.low_time
|
||||
or saif_signal.transitions != other_signal.transitions):
|
||||
saif_error("Incompatible signal bit parameters in "
|
||||
f"{signal_name}\n")
|
||||
|
||||
f"{signal_name}\n")
|
||||
if len(first.child_instances) != len(second.child_instances):
|
||||
saif_error(f"Number of child instances doesn't match in {first.scope_name}: "
|
||||
f"{len(first.child_instances)} != {len(second.child_instances)}")
|
||||
|
||||
f"{len(first.child_instances)} != {len(second.child_instances)}")
|
||||
for instance_name, instance in first.child_instances.items():
|
||||
if instance_name not in second.child_instances:
|
||||
saif_error(f"Instance {instance_name} doesn't exist in the second object\n")
|
||||
|
||||
compare_saif_instances(instance, second.child_instances[instance_name])
|
||||
|
||||
|
||||
def compare_saif_contents(first_file: str, second_file: str):
|
||||
"""Test if second SAIF file has the same values as the first"""
|
||||
|
||||
first_saif = SAIFParser()
|
||||
first_saif.parse(first_file)
|
||||
|
||||
second_saif = SAIFParser()
|
||||
second_saif.parse(second_file)
|
||||
|
||||
if first_saif.duration != second_saif.duration:
|
||||
saif_error(f"Duration of trace doesn't match: {first_saif.duration} != {second_saif.duration}")
|
||||
|
||||
saif_error("Duration of trace doesn't match: "
|
||||
f"{first_saif.duration} != {second_saif.duration}")
|
||||
if first_saif.divider != second_saif.divider:
|
||||
saif_error(f"Dividers don't match: {first_saif.divider} != {second_saif.divider}")
|
||||
|
||||
if first_saif.timescale != second_saif.timescale:
|
||||
saif_error(f"Timescale doesn't match: {first_saif.timescale} != {second_saif.timescale}")
|
||||
|
||||
if len(first_saif.top_instances) != len(second_saif.top_instances):
|
||||
saif_error("Number of top instances doesn't match: "
|
||||
f"{len(first_saif.top_instances)} != {len(second_saif.top_instances)}")
|
||||
|
||||
f"{len(first_saif.top_instances)} != {len(second_saif.top_instances)}")
|
||||
for top_instance_name, top_instance in first_saif.top_instances.items():
|
||||
if top_instance_name not in second_saif.top_instances:
|
||||
saif_error(f"Top instance {top_instance_name} missing in other SAIF")
|
||||
|
||||
compare_saif_instances(top_instance, second_saif.top_instances[top_instance_name])
|
||||
|
||||
return SUCCESS_CODE
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""""")
|
||||
|
||||
parser.add_argument('--first',
|
||||
action='store',
|
||||
help='First SAIF file')
|
||||
|
||||
parser.add_argument('--second',
|
||||
action='store',
|
||||
help='Second SAIF file')
|
||||
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""verilator_saif_diff checks if two SAIF files are logically-identical. It returns first encountered difference as output.
|
||||
Run as:
|
||||
cd $VERILATOR_ROOT
|
||||
nodist/code_coverage --first example.saif --second other.saif""")
|
||||
parser.add_argument('--first', action='store', help='First SAIF file')
|
||||
parser.add_argument('--second', action='store', help='Second SAIF file')
|
||||
parser.set_defaults(stop=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
compare_saif_contents(args.first, args.second)
|
||||
except Exception as error:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
(SAIFILE
|
||||
(SAIFVERSION "2.0")
|
||||
(DIRECTION "backward")
|
||||
(DESIGN "t")
|
||||
(DIVIDER / )
|
||||
(TIMESCALE 1ps)
|
||||
(DURATION 1004)
|
||||
(INSTANCE top
|
||||
(INSTANCE t
|
||||
(NET
|
||||
(clk (T0 505) (T1 499) (TX 0) (TC 199))
|
||||
(cyc\[0\] (T0 504) (T1 500) (TX 0) (TC 100))
|
||||
(cyc\[1\] (T0 504) (T1 500) (TX 0) (TC 50))
|
||||
(cyc\[2\] (T0 520) (T1 484) (TX 0) (TC 25))
|
||||
(cyc\[3\] (T0 524) (T1 480) (TX 0) (TC 12))
|
||||
(cyc\[4\] (T0 524) (T1 480) (TX 0) (TC 6))
|
||||
(cyc\[5\] (T0 640) (T1 364) (TX 0) (TC 3))
|
||||
(cyc\[6\] (T0 640) (T1 364) (TX 0) (TC 1))
|
||||
(rstn (T0 110) (T1 894) (TX 0) (TC 1))
|
||||
(fst_parameter\[0\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_parameter\[1\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_parameter\[3\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_parameter\[4\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_parameter\[5\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_parameter\[6\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_lparam\[3\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_lparam\[6\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_lparam\[7\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_lparam\[8\] (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_supply1 (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(fst_tri1 (T0 0) (T1 1004) (TX 0) (TC 1))
|
||||
(state\[0\] (T0 414) (T1 590) (TX 0) (TC 46))
|
||||
(state\[1\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state\[2\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state\[3\] (T0 544) (T1 460) (TX 0) (TC 44))
|
||||
(state\[4\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
)
|
||||
(INSTANCE test
|
||||
(NET
|
||||
(clk (T0 505) (T1 499) (TX 0) (TC 199))
|
||||
(rstn (T0 110) (T1 894) (TX 0) (TC 1))
|
||||
(state\[0\] (T0 414) (T1 590) (TX 0) (TC 46))
|
||||
(state\[1\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state\[2\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state\[3\] (T0 544) (T1 460) (TX 0) (TC 44))
|
||||
(state\[4\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state_w\[0\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_w\[1\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_w\[2\] (T0 434) (T1 570) (TX 0) (TC 46))
|
||||
(state_w\[3\] (T0 530) (T1 474) (TX 0) (TC 47))
|
||||
(state_w\[4\] (T0 424) (T1 580) (TX 0) (TC 48))
|
||||
(state_array[0]\[0\] (T0 414) (T1 590) (TX 0) (TC 46))
|
||||
(state_array[0]\[1\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state_array[0]\[2\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[0]\[3\] (T0 544) (T1 460) (TX 0) (TC 44))
|
||||
(state_array[0]\[4\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state_array[1]\[0\] (T0 420) (T1 584) (TX 0) (TC 47))
|
||||
(state_array[1]\[1\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[1]\[2\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[1]\[3\] (T0 540) (T1 464) (TX 0) (TC 45))
|
||||
(state_array[1]\[4\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[2]\[0\] (T0 424) (T1 580) (TX 0) (TC 48))
|
||||
(state_array[2]\[1\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[2]\[2\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[2]\[3\] (T0 534) (T1 470) (TX 0) (TC 46))
|
||||
(state_array[2]\[4\] (T0 530) (T1 474) (TX 0) (TC 47))
|
||||
)
|
||||
(INSTANCE unnamedblk1
|
||||
(NET
|
||||
(i\[0\] (T0 10) (T1 994) (TX 0) (TC 1))
|
||||
(i\[1\] (T0 10) (T1 994) (TX 0) (TC 1))
|
||||
)
|
||||
)
|
||||
(INSTANCE unnamedblk2
|
||||
(NET
|
||||
(i\[1\] (T0 120) (T1 884) (TX 0) (TC 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
if not test.have_sc:
|
||||
test.skip("No SystemC installed")
|
||||
|
||||
test.compile(verilator_flags2=["--trace-saif --sc"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.saif_identical(test.trace_filename, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// Author: Yu-Sheng Lin johnjohnlys@media.ee.ntu.edu.tw
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
int cyc;
|
||||
reg rstn;
|
||||
|
||||
parameter real fst_gparam_real = 1.23;
|
||||
localparam real fst_lparam_real = 4.56;
|
||||
real fst_real = 1.23;
|
||||
integer fst_integer;
|
||||
bit fst_bit;
|
||||
logic fst_logic;
|
||||
int fst_int;
|
||||
shortint fst_shortint;
|
||||
longint fst_longint;
|
||||
byte fst_byte;
|
||||
|
||||
parameter fst_parameter = 123;
|
||||
localparam fst_lparam = 456;
|
||||
supply0 fst_supply0;
|
||||
supply1 fst_supply1;
|
||||
tri0 fst_tri0;
|
||||
tri1 fst_tri1;
|
||||
tri fst_tri;
|
||||
wire fst_wire;
|
||||
|
||||
logic [4:0] state;
|
||||
|
||||
Test test (/*AUTOINST*/
|
||||
// Outputs
|
||||
.state (state[4:0]),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.rstn (rstn));
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
rstn <= ~'1;
|
||||
end
|
||||
else if (cyc<10) begin
|
||||
rstn <= ~'1;
|
||||
end
|
||||
else if (cyc<90) begin
|
||||
rstn <= ~'0;
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module Test (
|
||||
input clk,
|
||||
input rstn,
|
||||
output logic [4:0] state
|
||||
);
|
||||
|
||||
logic [4:0] state_w;
|
||||
logic [4:0] state_array [3];
|
||||
assign state = state_array[0];
|
||||
|
||||
always_comb begin
|
||||
state_w[4] = state_array[2][0];
|
||||
state_w[3] = state_array[2][4];
|
||||
state_w[2] = state_array[2][3] ^ state_array[2][0];
|
||||
state_w[1] = state_array[2][2];
|
||||
state_w[0] = state_array[2][1];
|
||||
end
|
||||
|
||||
always_ff @(posedge clk or negedge rstn) begin
|
||||
if (!rstn) begin
|
||||
for (int i = 0; i < 3; i++)
|
||||
state_array[i] <= 'b1;
|
||||
end
|
||||
else begin
|
||||
for (int i = 0; i < 2; i++)
|
||||
state_array[i] <= state_array[i+1];
|
||||
state_array[2] <= state_w;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue