mirror of
https://github.com/verilator/verilator.git
synced 2026-08-30 01:38:21 +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.
429 lines
19 KiB
C++
429 lines
19 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 FST format implementation code
|
|
///
|
|
/// This file must be compiled and linked against all Verilated objects
|
|
/// that use --trace-fst.
|
|
///
|
|
/// Use "verilator --trace-fst" to add this to the Makefile for the linker.
|
|
///
|
|
//=============================================================================
|
|
|
|
// clang-format off
|
|
|
|
#include "verilated.h"
|
|
#include "verilated_fst_c.h"
|
|
|
|
// Include fstcpp cpp file directly
|
|
#include "fstcpp/fstcpp_variable_info.cpp"
|
|
#include "fstcpp/fstcpp_writer.cpp"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
|
# include <io.h>
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
// clang-format on
|
|
|
|
//=============================================================================
|
|
// Check that forward declared types matches the FST API types
|
|
|
|
static_assert(std::is_same<vlFstHandle, fst::Handle>::value, "vlFstHandle mismatch");
|
|
static_assert(std::is_same<vlFstEnumHandle, fst::EnumHandle>::value, "vlFstHandle mismatch");
|
|
|
|
//=============================================================================
|
|
// Specialization of the generics for this trace format
|
|
|
|
#define VL_SUB_T VerilatedFst
|
|
#define VL_BUF_T VerilatedFstBuffer
|
|
#include "verilated_trace_imp.h"
|
|
#undef VL_SUB_T
|
|
#undef VL_BUF_T
|
|
|
|
//=============================================================================
|
|
// VerilatedFst
|
|
|
|
VerilatedFst::VerilatedFst(void* /*fst*/) {}
|
|
|
|
VerilatedFst::~VerilatedFst() {
|
|
if (m_fst) VL_DO_CLEAR(delete m_fst, m_fst = nullptr); // LCOV_EXCL_BR_LINE
|
|
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = nullptr); // LCOV_EXCL_BR_LINE
|
|
if (m_strbufp) VL_DO_CLEAR(delete[] m_strbufp, m_strbufp = nullptr); // LCOV_EXCL_BR_LINE
|
|
}
|
|
|
|
void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
m_fst = new fst::Writer{filename}; // LCOV_EXCL_BR_LINE
|
|
m_fst->setWriterPackType(fst::WriterPackType::LZ4);
|
|
m_fst->setTimecale(int8_t(round(log10(timeRes()))));
|
|
// if (m_useFstWriterThread) fstWriterSetParallelMode(m_fst, 1);
|
|
m_fst->setWriter("Generated by VerilatedFst");
|
|
constDump(true); // First dump must contain the const signals
|
|
fullDump(true); // First dump must be full for fst
|
|
|
|
Super::traceInit();
|
|
|
|
// convert m_code2symbol into an array for fast lookup
|
|
if (!m_symbolp) {
|
|
m_symbolp = new fst::Handle[nextCode()]{0}; // LCOV_EXCL_BR_LINE
|
|
for (const auto& i : m_code2symbol) m_symbolp[i.first] = i.second;
|
|
}
|
|
m_code2symbol.clear();
|
|
|
|
// Allocate string buffer for arrays
|
|
if (!m_strbufp) m_strbufp = new char[maxBits() + 32];
|
|
}
|
|
|
|
void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
Super::closeBase();
|
|
emitTimeChangeMaybe();
|
|
if (m_fst) m_fst->close(); // LCOV_EXCL_BR_LINE
|
|
m_fst = nullptr;
|
|
}
|
|
|
|
void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
|
const VerilatedLockGuard lock{m_mutex};
|
|
Super::flushBase();
|
|
emitTimeChangeMaybe();
|
|
if (m_fst) m_fst->flushValueChangeData(); // LCOV_EXCL_BR_LINE
|
|
}
|
|
|
|
void VerilatedFst::emitTimeChange(uint64_t timeui) {
|
|
if (!timeui) m_fst->emitTimeChange(timeui);
|
|
m_timeui = timeui;
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFst::emitTimeChangeMaybe() {
|
|
if (VL_UNLIKELY(m_timeui)) {
|
|
m_fst->emitTimeChange(m_timeui);
|
|
m_timeui = 0;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// Decl
|
|
|
|
void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, uint32_t elements,
|
|
unsigned int minValbits, const char** itemNamesp,
|
|
const char** itemValuesp) {
|
|
std::vector<std::pair<const char*, const char*>> itemNameValuesp{elements};
|
|
for (uint32_t i = 0; i < elements; ++i) {
|
|
itemNameValuesp[i].first = itemNamesp[i];
|
|
itemNameValuesp[i].second = itemValuesp[i];
|
|
}
|
|
const fst::EnumHandle enumNum = m_fst->createEnumTable(name, minValbits, itemNameValuesp);
|
|
const bool newEntry = m_local2fstdtype[initUserp()].emplace(dtypenum, enumNum).second;
|
|
assert(newEntry);
|
|
(void)newEntry; // Prevent unused variable warning when asserts are disabled
|
|
}
|
|
|
|
void VerilatedFst::pushPrefix(const char* namep, VerilatedTracePrefixType type, int left,
|
|
int right) {
|
|
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;
|
|
}
|
|
|
|
bool isProperScope = true;
|
|
switch (type) {
|
|
case VerilatedTracePrefixType::ARRAY_PACKED:
|
|
case VerilatedTracePrefixType::ARRAY_UNPACKED: isProperScope = false; break;
|
|
default: break;
|
|
}
|
|
|
|
// This code assumes a signal at a given prefix level is declared before
|
|
// any pushPrefix are done at that same level.
|
|
const std::string newPrefix = prevPrefix + name;
|
|
m_prefixStack.emplace_back(newPrefix + (isProperScope ? " " : ""), type);
|
|
|
|
const uint32_t l = static_cast<uint32_t>(left);
|
|
const uint32_t r = static_cast<uint32_t>(right);
|
|
const uint64_t lr = static_cast<uint64_t>(l) << 32 | static_cast<uint64_t>(r);
|
|
|
|
switch (type) {
|
|
case VerilatedTracePrefixType::SCOPE_MODULE:
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::VCD_MODULE, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::VCD_INTERFACE, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::STRUCT_PACKED:
|
|
m_fst->setAttrBegin(fst::Hierarchy::AttrType::PACK,
|
|
fst::Hierarchy::AttrSubType::PACK_PACKED, "members", l);
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::VCD_STRUCT, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::STRUCT_UNPACKED:
|
|
m_fst->setAttrBegin(fst::Hierarchy::AttrType::PACK,
|
|
fst::Hierarchy::AttrSubType::PACK_UNPACKED, "members", l);
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::VCD_STRUCT, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::UNION_PACKED:
|
|
m_fst->setAttrBegin(fst::Hierarchy::AttrType::PACK,
|
|
fst::Hierarchy::AttrSubType::PACK_PACKED, "members", l);
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::VCD_UNION, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::ARRAY_PACKED:
|
|
m_fst->setAttrBegin(fst::Hierarchy::AttrType::ARRAY,
|
|
fst::Hierarchy::AttrSubType::ARRAY_PACKED, "bounds", lr);
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::SV_ARRAY, name, std::string{});
|
|
break;
|
|
case VerilatedTracePrefixType::ARRAY_UNPACKED:
|
|
m_fst->setAttrBegin(fst::Hierarchy::AttrType::ARRAY,
|
|
fst::Hierarchy::AttrSubType::ARRAY_UNPACKED, "bounds", lr);
|
|
m_fst->setScope(fst::Hierarchy::ScopeType::SV_ARRAY, name, std::string{});
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void VerilatedFst::popPrefix() {
|
|
assert(!m_prefixStack.empty());
|
|
if (m_prefixStack.back().second != VerilatedTracePrefixType::ROOTIO_WRAPPER) {
|
|
m_fst->upscope();
|
|
}
|
|
m_prefixStack.pop_back();
|
|
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
|
}
|
|
|
|
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, bool array, int arraynum, bool bussed,
|
|
int msb, int lsb) {
|
|
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
|
|
|
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
|
|
|
const bool enabled = Super::declCode(code, hierarchicalName, bits);
|
|
if (!enabled) return;
|
|
|
|
assert(hierarchicalName.rfind(' ') != std::string::npos);
|
|
std::stringstream name_ss;
|
|
name_ss << lastWord(hierarchicalName);
|
|
if (array) name_ss << "[" << arraynum << "]";
|
|
if (bussed) name_ss << " [" << msb << ":" << lsb << "]";
|
|
const std::string name_str = name_ss.str();
|
|
|
|
if (dtypenum > 0) { m_fst->emitEnumTableRef(m_local2fstdtype.at(initUserp()).at(dtypenum)); }
|
|
|
|
fst::Hierarchy::VarDirection varDir = fst::Hierarchy::VarDirection::IMPLICIT;
|
|
switch (direction) {
|
|
case VerilatedTraceSigDirection::INOUT: varDir = fst::Hierarchy::VarDirection::INOUT; break;
|
|
case VerilatedTraceSigDirection::OUTPUT: varDir = fst::Hierarchy::VarDirection::OUTPUT; break;
|
|
case VerilatedTraceSigDirection::INPUT: varDir = fst::Hierarchy::VarDirection::INPUT; break;
|
|
case VerilatedTraceSigDirection::NONE: varDir = fst::Hierarchy::VarDirection::IMPLICIT; break;
|
|
}
|
|
|
|
fst::Hierarchy::VarType varType;
|
|
// Doubles have special decoding properties, so must indicate if a double
|
|
if (type == VerilatedTraceSigType::DOUBLE) {
|
|
if (kind == VerilatedTraceSigKind::PARAMETER) {
|
|
varType = fst::Hierarchy::VarType::VCD_REAL_PARAMETER;
|
|
} else {
|
|
varType = fst::Hierarchy::VarType::VCD_REAL;
|
|
}
|
|
}
|
|
// clang-format off
|
|
else if (kind == VerilatedTraceSigKind::PARAMETER) varType = fst::Hierarchy::VarType::VCD_PARAMETER;
|
|
else if (kind == VerilatedTraceSigKind::SUPPLY0) varType = fst::Hierarchy::VarType::VCD_SUPPLY0;
|
|
else if (kind == VerilatedTraceSigKind::SUPPLY1) varType = fst::Hierarchy::VarType::VCD_SUPPLY1;
|
|
else if (kind == VerilatedTraceSigKind::TRI) varType = fst::Hierarchy::VarType::VCD_TRI;
|
|
else if (kind == VerilatedTraceSigKind::TRI0) varType = fst::Hierarchy::VarType::VCD_TRI0;
|
|
else if (kind == VerilatedTraceSigKind::TRI1) varType = fst::Hierarchy::VarType::VCD_TRI1;
|
|
else if (kind == VerilatedTraceSigKind::TRIAND) varType = fst::Hierarchy::VarType::VCD_TRIAND;
|
|
else if (kind == VerilatedTraceSigKind::TRIOR) varType = fst::Hierarchy::VarType::VCD_TRIOR;
|
|
else if (kind == VerilatedTraceSigKind::TRIREG) varType = fst::Hierarchy::VarType::VCD_TRIREG; // LCOV_EXCL_BR_LINE
|
|
else if (kind == VerilatedTraceSigKind::WIRE) varType = fst::Hierarchy::VarType::VCD_WIRE;
|
|
//
|
|
else if (type == VerilatedTraceSigType::INTEGER) varType = fst::Hierarchy::VarType::VCD_INTEGER;
|
|
else if (type == VerilatedTraceSigType::BIT) varType = fst::Hierarchy::VarType::SV_BIT;
|
|
else if (type == VerilatedTraceSigType::LOGIC) varType = fst::Hierarchy::VarType::SV_LOGIC;
|
|
else if (type == VerilatedTraceSigType::INT) varType = fst::Hierarchy::VarType::SV_INT;
|
|
else if (type == VerilatedTraceSigType::SHORTINT) varType = fst::Hierarchy::VarType::SV_SHORTINT;
|
|
else if (type == VerilatedTraceSigType::LONGINT) varType = fst::Hierarchy::VarType::SV_LONGINT;
|
|
else if (type == VerilatedTraceSigType::BYTE) varType = fst::Hierarchy::VarType::SV_BYTE;
|
|
else if (type == VerilatedTraceSigType::EVENT) varType = fst::Hierarchy::VarType::VCD_EVENT;
|
|
else if (type == VerilatedTraceSigType::TIME) varType = fst::Hierarchy::VarType::VCD_TIME; // LCOV_EXCL_BR_LINE
|
|
else { assert(0); /* Unreachable */ }
|
|
// clang-format on
|
|
|
|
const auto it = vlstd::as_const(m_code2symbol).find(code);
|
|
if (it == m_code2symbol.end()) { // New
|
|
m_code2symbol[code] = m_fst->createVar(varType, varDir, bits, name_str.c_str(), 0);
|
|
} else { // Alias
|
|
m_fst->createVar(varType, varDir, bits, name_str.c_str(), it->second);
|
|
}
|
|
}
|
|
|
|
// versions to call when the sig is not array member
|
|
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, false, 0, 0);
|
|
}
|
|
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, false, 0, 0);
|
|
}
|
|
void VerilatedFst::declBus(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declQuad(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declWide(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type) {
|
|
declare(code, name, dtypenum, direction, kind, type, false, -1, false, 63, 0);
|
|
}
|
|
|
|
// versions to call when the sig is array member
|
|
void VerilatedFst::declEventArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int arraynum) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, false, 0, 0);
|
|
}
|
|
void VerilatedFst::declBitArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int arraynum) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, false, 0, 0);
|
|
}
|
|
void VerilatedFst::declBusArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int arraynum, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declQuadArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int arraynum, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declWideArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
|
VerilatedTraceSigType type, int arraynum, int msb, int lsb) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, true, msb, lsb);
|
|
}
|
|
void VerilatedFst::declDoubleArray(uint32_t code, const char* name, int dtypenum,
|
|
VerilatedTraceSigDirection direction,
|
|
VerilatedTraceSigKind kind, VerilatedTraceSigType type,
|
|
int arraynum) {
|
|
declare(code, name, dtypenum, direction, kind, type, true, arraynum, false, 63, 0);
|
|
}
|
|
//=============================================================================
|
|
// Get/commit trace buffer
|
|
|
|
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer(uint32_t /*fidx*/) { return new Buffer{*this}; }
|
|
|
|
void VerilatedFst::commitTraceBuffer(VerilatedFst::Buffer* bufp) { delete bufp; }
|
|
|
|
//=============================================================================
|
|
// VerilatedFstBuffer implementation
|
|
|
|
//=============================================================================
|
|
// Trace rendering primitives
|
|
|
|
// 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 VerilatedFstBuffer::emitEvent(uint32_t code) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], 1);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], uint64_t(newval));
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], newval);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], newval);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], newval);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], newval);
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitWData(uint32_t code, WDataInP newval, int) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
m_fst->emitValueChange(m_symbolp[code], newval.datap());
|
|
}
|
|
|
|
VL_ATTR_ALWINLINE
|
|
void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) {
|
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
|
m_owner.emitTimeChangeMaybe();
|
|
uint64_t newval_u64;
|
|
std::memcpy(&newval_u64, &newval, sizeof(newval_u64));
|
|
m_fst->emitValueChange(m_symbolp[code], newval_u64);
|
|
}
|