mirror of
https://github.com/verilator/verilator.git
synced 2026-08-29 17:28:46 +02:00
Change WDataInP/WDataOutP to be opaque handles types instead of aliases to raw pointers. This subsequently eliminates needing an implicit cast operator in VlWide, which is replaced with implicit constructors of WDataInP/WDataOutP that can create a handle from a VlWide. This eliminates some unsafe conversions that the previous implicit cast operator unintentionally enabled (e.g. #7618). It also eliminates having to insert ".data()" in various places int he generated code, which simplifies internals (the only place ".data()" should be needed is in calls to variadic functions where the expected type of the argument is not WDataInP/WDataOutP). The handles otherwise behave like pointers, implementing the minimal amount of operators required to code the runtime. The handle is still only a single pointer, and will be passed in registers as before, so this patch should be performance neutral. As part of this removed WData, which used to be an alias for EData. All uses are now either EData*, WDataInP, WDataOutP, or VlWide directly.
685 lines
25 KiB
C++
685 lines
25 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//=============================================================================
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
// 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-FileCopyrightText: 2001-2026 Wilson Snyder
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//=============================================================================
|
|
///
|
|
/// \file
|
|
/// \brief Verilated C++ tracing in SAIF format implementation code
|
|
///
|
|
/// This file must be compiled and linked against all Verilated objects
|
|
/// that use --trace-saif.
|
|
///
|
|
/// Use "verilator --trace-saif" to add this to the Makefile for the linker.
|
|
///
|
|
//=============================================================================
|
|
|
|
// clang-format off
|
|
|
|
#include "verilatedos.h"
|
|
#include "verilated.h"
|
|
#include "verilated_saif_c.h"
|
|
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <fcntl.h>
|
|
#include <string>
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
|
# include <io.h>
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#ifndef O_LARGEFILE // WIN32 headers omit this
|
|
# define O_LARGEFILE 0
|
|
#endif
|
|
#ifndef O_NONBLOCK // WIN32 headers omit this
|
|
# define O_NONBLOCK 0
|
|
#endif
|
|
#ifndef O_CLOEXEC // WIN32 headers omit this
|
|
# define O_CLOEXEC 0
|
|
#endif
|
|
|
|
// clang-format on
|
|
|
|
//=============================================================================
|
|
// Specialization of the generics for this trace format
|
|
|
|
#define VL_SUB_T VerilatedSaif
|
|
#define VL_BUF_T VerilatedSaifBuffer
|
|
#include "verilated_trace_imp.h"
|
|
#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; // 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(uint64_t startTime, uint32_t width, VerilatedSaifActivityBit* bits)
|
|
: m_lastTime{startTime}
|
|
, 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, WDataInP newval, 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, uint64_t startTime);
|
|
|
|
// CONSTRUCTORS
|
|
VerilatedSaifActivityAccumulator() = default;
|
|
|
|
VerilatedSaifActivityAccumulator(VerilatedSaifActivityAccumulator&&) = default;
|
|
VerilatedSaifActivityAccumulator& operator=(VerilatedSaifActivityAccumulator&&) = default;
|
|
|
|
private:
|
|
VL_UNCOPYABLE(VerilatedSaifActivityAccumulator);
|
|
};
|
|
|
|
//=============================================================================
|
|
//=============================================================================
|
|
//=============================================================================
|
|
// VerilatedSaifActivityVar implementation
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedSaifActivityVar::emitBit(const uint64_t time, const CData newval) {
|
|
assert(m_lastTime <= time);
|
|
m_bits[0].aggregateVal(time - m_lastTime, newval);
|
|
updateLastTime(time);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedSaifActivityVar::emitWData(const uint64_t time, WDataInP newval,
|
|
const uint32_t bits) {
|
|
assert(m_lastTime <= time);
|
|
const uint64_t dt = time - m_lastTime;
|
|
for (std::size_t i = 0; i < std::min(m_width, bits); ++i) {
|
|
const size_t wordIndex = i / VL_EDATASIZE;
|
|
m_bits[i].aggregateVal(dt, (newval[wordIndex] >> VL_BITBIT_E(i)) & 1);
|
|
}
|
|
|
|
updateLastTime(time);
|
|
}
|
|
|
|
VerilatedSaifActivityBit& VerilatedSaifActivityVar::bit(const std::size_t index) {
|
|
assert(index < m_width);
|
|
return m_bits[index];
|
|
}
|
|
|
|
//=============================================================================
|
|
//=============================================================================
|
|
//=============================================================================
|
|
// VerilatedSaifActivityAccumulator implementation
|
|
|
|
void VerilatedSaifActivityAccumulator::declare(uint32_t code, const std::string& absoluteScopePath,
|
|
std::string variableName, int bits, bool array,
|
|
int arraynum, uint64_t startTime) {
|
|
const size_t block_size = 1024;
|
|
if (m_activityArena.empty()
|
|
|| m_activityArena.back().size() + bits > m_activityArena.back().capacity()) {
|
|
m_activityArena.emplace_back();
|
|
m_activityArena.back().reserve(block_size);
|
|
}
|
|
const size_t bitsIdx = m_activityArena.back().size();
|
|
m_activityArena.back().resize(m_activityArena.back().size() + bits);
|
|
|
|
if (array) {
|
|
variableName += '[';
|
|
variableName += std::to_string(arraynum);
|
|
variableName += ']';
|
|
}
|
|
m_scopeToActivities[absoluteScopePath].emplace_back(code, variableName);
|
|
m_activity.emplace(code, VerilatedSaifActivityVar{startTime, static_cast<uint32_t>(bits),
|
|
m_activityArena.back().data() + bitsIdx});
|
|
}
|
|
|
|
//=============================================================================
|
|
//=============================================================================
|
|
//=============================================================================
|
|
// VerilatedSaif implementation
|
|
|
|
VerilatedSaif::VerilatedSaif(void* /*filep*/) {}
|
|
|
|
void VerilatedSaif::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
if (isOpen()) return;
|
|
|
|
m_startTime = currentTime();
|
|
m_filename = filename; // "" is ok, as someone may overload open
|
|
m_filep = ::open(m_filename.c_str(),
|
|
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
|
m_isOpen = true;
|
|
m_activityAccumulators.emplace_back(std::make_unique<VerilatedSaifActivityAccumulator>());
|
|
|
|
initializeSaifFileContents();
|
|
|
|
Super::traceInit();
|
|
}
|
|
|
|
void VerilatedSaif::initializeSaifFileContents() {
|
|
printStr("// Generated by verilated_saif\n");
|
|
printStr("(SAIFILE\n");
|
|
printStr("(SAIFVERSION \"2.0\")\n");
|
|
printStr("(DIRECTION \"backward\")\n");
|
|
printStr("(PROGRAM_NAME \"Verilator\")\n");
|
|
printStr("(DIVIDER / )\n");
|
|
printStr("(TIMESCALE ");
|
|
printStr(timeResStr());
|
|
printStr(")\n");
|
|
}
|
|
|
|
void VerilatedSaif::emitTimeChange(uint64_t timeui) { m_time = timeui; }
|
|
|
|
VerilatedSaif::~VerilatedSaif() { close(); }
|
|
|
|
void VerilatedSaif::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
// This function is on the flush() call path
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
if (!isOpen()) return;
|
|
|
|
finalizeSaifFileContents();
|
|
clearCurrentlyCollectedData();
|
|
|
|
writeBuffered(true);
|
|
::close(m_filep);
|
|
m_isOpen = false;
|
|
|
|
Super::closeBase();
|
|
}
|
|
|
|
void VerilatedSaif::finalizeSaifFileContents() {
|
|
printStr("(DURATION ");
|
|
printStr(std::to_string(currentTime() - m_startTime));
|
|
printStr(")\n");
|
|
|
|
incrementIndent();
|
|
for (const auto& topScope : m_scopes) recursivelyPrintScopes(*topScope);
|
|
decrementIndent();
|
|
|
|
printStr(")\n"); // SAIFILE
|
|
}
|
|
|
|
void VerilatedSaif::recursivelyPrintScopes(const VerilatedSaifActivityScope& scope) {
|
|
openInstanceScope(scope.name());
|
|
printScopeActivities(scope);
|
|
for (const auto& childScope : scope.childScopes()) recursivelyPrintScopes(*childScope);
|
|
closeInstanceScope();
|
|
}
|
|
|
|
void VerilatedSaif::openInstanceScope(const std::string& instanceName) {
|
|
printIndent();
|
|
printStr("(INSTANCE ");
|
|
printStr(instanceName);
|
|
printStr("\n");
|
|
incrementIndent();
|
|
}
|
|
|
|
void VerilatedSaif::closeInstanceScope() {
|
|
decrementIndent();
|
|
printIndent();
|
|
printStr(")\n"); // INSTANCE
|
|
}
|
|
|
|
void VerilatedSaif::printScopeActivities(const VerilatedSaifActivityScope& scope) {
|
|
bool anyNetWritten = false;
|
|
|
|
for (auto& accumulator : m_activityAccumulators) {
|
|
anyNetWritten |= printScopeActivitiesFromAccumulatorIfPresent(scope.path(), *accumulator,
|
|
anyNetWritten);
|
|
}
|
|
|
|
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, anyNetWritten);
|
|
}
|
|
|
|
return anyNetWritten;
|
|
}
|
|
|
|
void VerilatedSaif::openNetScope() {
|
|
printIndent();
|
|
printStr("(NET\n");
|
|
incrementIndent();
|
|
}
|
|
|
|
void VerilatedSaif::closeNetScope() {
|
|
decrementIndent();
|
|
printIndent();
|
|
printStr(")\n"); // NET
|
|
}
|
|
|
|
bool VerilatedSaif::printActivityStats(VerilatedSaifActivityVar& activity,
|
|
const std::string& activityName, bool anyNetWritten) {
|
|
for (size_t i = 0; i < activity.width(); ++i) {
|
|
VerilatedSaifActivityBit& bit = activity.bit(i);
|
|
|
|
bit.aggregateVal(currentTime() - activity.lastUpdateTime(), bit.bitValue());
|
|
|
|
if (!anyNetWritten) {
|
|
openNetScope();
|
|
anyNetWritten = true;
|
|
}
|
|
|
|
printIndent();
|
|
printStr("(");
|
|
printStr(activityName);
|
|
if (activity.width() > 1) {
|
|
printStr("\\[");
|
|
printStr(std::to_string(i));
|
|
printStr("\\]");
|
|
}
|
|
|
|
// We only have two-value logic so TZ, TX and TB will always be 0
|
|
printStr(" (T0 ");
|
|
printStr(std::to_string(currentTime() - m_startTime - bit.highTime()));
|
|
printStr(") (T1 ");
|
|
printStr(std::to_string(bit.highTime()));
|
|
printStr(") (TZ 0) (TX 0) (TB 0) (TC ");
|
|
printStr(std::to_string(bit.toggleCount()));
|
|
printStr("))\n");
|
|
}
|
|
|
|
activity.updateLastTime(currentTime());
|
|
|
|
return anyNetWritten;
|
|
}
|
|
|
|
void VerilatedSaif::clearCurrentlyCollectedData() {
|
|
m_currentScope = nullptr;
|
|
m_scopes.clear();
|
|
m_activityAccumulators.clear();
|
|
}
|
|
|
|
void VerilatedSaif::printStr(const char* str) {
|
|
m_buffer.append(str);
|
|
writeBuffered(false);
|
|
}
|
|
|
|
void VerilatedSaif::printStr(const std::string& str) {
|
|
m_buffer.append(str);
|
|
writeBuffered(false);
|
|
}
|
|
|
|
void VerilatedSaif::writeBuffered(bool force) {
|
|
if (VL_UNLIKELY(m_buffer.size() >= WRITE_BUFFER_SIZE || force)) {
|
|
if (VL_UNLIKELY(!m_buffer.empty())) {
|
|
const ssize_t n = ::write(m_filep, m_buffer.data(), m_buffer.size());
|
|
assert(n == static_cast<ssize_t>(m_buffer.size()));
|
|
m_buffer = "";
|
|
m_buffer.reserve(WRITE_BUFFER_SIZE * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// Definitions
|
|
|
|
void VerilatedSaif::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
Super::flushBase();
|
|
}
|
|
|
|
void VerilatedSaif::incrementIndent() { m_indent += 1; }
|
|
|
|
void VerilatedSaif::decrementIndent() { m_indent -= 1; }
|
|
|
|
void VerilatedSaif::printIndent() {
|
|
printStr(std::string(m_indent, ' ')); // Must use () constructor
|
|
}
|
|
|
|
void VerilatedSaif::pushPrefix(const char* namep, VerilatedTracePrefixType type) {
|
|
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
|
|
const std::string name{namep};
|
|
// 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 $rootio scope, but the signals
|
|
// further down will be peers, not children (as usual for name()!="").
|
|
const std::string prevPrefix = m_prefixStack.back().first;
|
|
if (name == "$rootio" && !prevPrefix.empty()) {
|
|
// Upper has name, we can suppress inserting $rootio, but still push so popPrefix works
|
|
m_prefixStack.emplace_back(prevPrefix, VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
|
return;
|
|
}
|
|
if (name.empty()) {
|
|
m_prefixStack.emplace_back(prevPrefix, VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
|
return;
|
|
}
|
|
|
|
if (type != VerilatedTracePrefixType::ARRAY_UNPACKED
|
|
&& type != VerilatedTracePrefixType::ARRAY_PACKED) {
|
|
|
|
std::string scopePath = prevPrefix + name;
|
|
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_scopes.emplace_back(std::move(newScope));
|
|
}
|
|
|
|
m_currentScope = newScopePtr;
|
|
}
|
|
|
|
const std::string newPrefix = prevPrefix + name;
|
|
const bool properScope = (type != VerilatedTracePrefixType::ARRAY_UNPACKED
|
|
&& type != VerilatedTracePrefixType::ARRAY_PACKED
|
|
&& type != VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
|
m_prefixStack.emplace_back(newPrefix + (properScope ? " " : ""), type);
|
|
}
|
|
|
|
void VerilatedSaif::popPrefix() {
|
|
if (m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_UNPACKED
|
|
&& m_prefixStack.back().second != VerilatedTracePrefixType::ARRAY_PACKED
|
|
&& m_prefixStack.back().second != VerilatedTracePrefixType::ROOTIO_WRAPPER
|
|
&& m_currentScope) {
|
|
m_currentScope = m_currentScope->parentScope();
|
|
}
|
|
m_prefixStack.pop_back();
|
|
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
|
}
|
|
|
|
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, m_startTime);
|
|
}
|
|
|
|
// versions to call when the sig is not array member
|
|
void VerilatedSaif::declEvent(const uint32_t code, const uint32_t fidx, const char* name) {
|
|
declare(code, fidx, name, "event", false, -1, false, 0, 0);
|
|
}
|
|
void VerilatedSaif::declBit(const uint32_t code, const uint32_t fidx, const char* name) {
|
|
declare(code, fidx, name, "wire", false, -1, false, 0, 0);
|
|
}
|
|
void VerilatedSaif::declBus(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declQuad(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declWide(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declDouble(const uint32_t code, const uint32_t fidx, const char* name) {
|
|
declare(code, fidx, name, "real", false, -1, false, 63, 0);
|
|
}
|
|
|
|
// versions to call when the sig is array member
|
|
void VerilatedSaif::declEventArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum) {
|
|
declare(code, fidx, name, "event", true, arraynum, false, 0, 0);
|
|
}
|
|
void VerilatedSaif::declBitArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum) {
|
|
declare(code, fidx, name, "wire", true, arraynum, false, 0, 0);
|
|
}
|
|
void VerilatedSaif::declBusArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum, const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declQuadArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum, const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declWideArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum, const int msb, const int lsb) {
|
|
declare(code, fidx, name, "wire", true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedSaif::declDoubleArray(const uint32_t code, const uint32_t fidx, const char* name,
|
|
const int arraynum) {
|
|
declare(code, fidx, name, "real", true, arraynum, false, 63, 0);
|
|
}
|
|
|
|
//=============================================================================
|
|
// Get/commit trace buffer
|
|
|
|
VerilatedSaif::Buffer* VerilatedSaif::getTraceBuffer(uint32_t /*fidx*/) {
|
|
return new Buffer{*this};
|
|
}
|
|
|
|
void VerilatedSaif::commitTraceBuffer(VerilatedSaif::Buffer* bufp) { delete bufp; }
|
|
|
|
//=============================================================================
|
|
//=============================================================================
|
|
//=============================================================================
|
|
// VerilatedSaifBuffer implementation
|
|
|
|
//=============================================================================
|
|
// emit* trace routines
|
|
|
|
// Note: emit* are only ever called from one place (full* in
|
|
// verilated_trace_imp.h, which is included in this file at the top),
|
|
// so always inline them.
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedSaifBuffer::emitEvent(const uint32_t code) {
|
|
// NOP
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedSaifBuffer::emitBit(const uint32_t code, const CData newval) {
|
|
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_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_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_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_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, WDataInP newval, const int bits) {
|
|
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(), newval, bits);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedSaifBuffer::emitDouble(const uint32_t code, const double newval) {
|
|
// NOP
|
|
}
|