verilator/include/verilated_sym_props.h

275 lines
11 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2003-2025 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
//
//*************************************************************************
///
/// \file
/// \brief Verilated symbol inspection header
///
/// This file is for inclusion by internal files that need to inspect
/// specific symbols. Applications typically use the VPI instead.
///
/// User wrapper code wanting to inspect the symbol table should use
/// verilated_syms.h instead.
///
//*************************************************************************
// These classes are thread safe, and read only.
#ifndef VERILATOR_VERILATED_SYM_PROPS_H_
#define VERILATOR_VERILATED_SYM_PROPS_H_
#include "verilatedos.h"
#include <vector>
//===========================================================================
// Verilator range
// Thread safety: Assume is constructed only with model, then any number of readers
// See also V3Ast::VNumRange
class VerilatedRange final {
int m_left = 0;
int m_right = 0;
protected:
friend class VerilatedVarProps;
friend class VerilatedScope;
VerilatedRange() = default;
void init(int left, int right) {
m_left = left;
m_right = right;
}
public:
VerilatedRange(int left, int right)
: m_left{left}
, m_right{right} {}
~VerilatedRange() = default;
int left() const VL_PURE { return m_left; }
int right() const VL_PURE { return m_right; }
int low() const VL_PURE { return (m_left < m_right) ? m_left : m_right; }
int high() const VL_PURE { return (m_left > m_right) ? m_left : m_right; }
int elements() const VL_PURE {
return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1));
}
int increment() const VL_PURE { return (m_left >= m_right) ? 1 : -1; }
};
//===========================================================================
// Verilator variable
// Thread safety: Assume is constructed only with model, then any number of readers
class VerilatedVarProps VL_NOT_FINAL {
// TYPES
static constexpr uint32_t MAGIC = 0xddc4f829UL;
// MEMBERS
const uint32_t m_magic; // Magic number
const VerilatedVarType m_vltype; // Data type
const VerilatedVarFlags m_vlflags; // Direction
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
std::vector<VerilatedRange> m_packed; // Packed array ranges
VerilatedRange m_packedDpi; // Flattened packed array range
void initUnpacked(int udims, const int* ulims) {
for (int i = 0; i < udims; ++i) {
const int uleft = ulims ? ulims[2 * i + 0] : 0;
const int uright = ulims ? ulims[2 * i + 1] : 0;
m_unpacked.emplace_back(uleft, uright);
}
}
void initPacked(int pdims, const int* plims) {
int packedSize = 1;
for (int i = 0; i < pdims; ++i) {
const int pleft = plims ? plims[2 * i + 0] : 0;
const int pright = plims ? plims[2 * i + 1] : 0;
m_packed.emplace_back(pleft, pright);
packedSize *= abs(pleft - pright) + 1;
}
if (pdims == 1) {
// Preserve packed array range if the packed component is 1-D
m_packedDpi = m_packed.front();
} else {
m_packedDpi = VerilatedRange{packedSize - 1, 0};
}
}
// CONSTRUCTORS
protected:
friend class VerilatedScope;
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims, int pdims)
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags{vlflags} {
// Only preallocate the ranges
initUnpacked(udims, nullptr);
initPacked(pdims, nullptr);
}
public:
class Unpacked {};
// Without packed
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) {} // Need () or GCC 4.8 false warning
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
initUnpacked(udims, ulims);
}
// With packed
class Packed {};
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
initPacked(pdims, plims);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
Packed, int pdims, const int* plims)
: m_magic{MAGIC}
, m_vltype{vltype}
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
initUnpacked(udims, ulims);
initPacked(pdims, plims);
}
~VerilatedVarProps() = default;
// METHODS
bool magicOk() const { return m_magic == MAGIC; }
VerilatedVarType vltype() const VL_MT_SAFE { return m_vltype; }
VerilatedVarFlags vldir() const {
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
}
uint32_t entSize() const VL_MT_SAFE;
uint32_t entBits() const VL_MT_SAFE {
uint32_t bits = 1;
for (auto it : m_packed) bits *= it.elements();
return bits;
}
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
// DPI compatible C standard layout
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
int udims() const VL_MT_SAFE { return m_unpacked.size(); }
int pdims() const VL_MT_SAFE { return m_packed.size(); }
int dims() const VL_MT_SAFE { return pdims() + udims(); }
const std::vector<VerilatedRange>& packedRanges() const VL_MT_SAFE { return m_packed; }
const std::vector<VerilatedRange>& unpackedRanges() const VL_MT_SAFE { return m_unpacked; }
const VerilatedRange* range(int dim) const VL_MT_SAFE {
if (dim < udims())
return &m_unpacked[dim];
else if (dim < dims())
return &m_packed[dim - udims()];
else
return nullptr;
}
// DPI accessors (with packed dimensions flattened!)
int left(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packedDpi.left()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
: 0;
}
int right(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packedDpi.right()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
: 0;
}
int low(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packedDpi.low()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
: 0;
}
int high(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packedDpi.high()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
: 0;
}
int increment(int dim) const {
return dim == 0 ? m_packedDpi.increment()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
: 0;
}
int elements(int dim) const VL_MT_SAFE {
return dim == 0 ? m_packedDpi.elements()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
: 0;
}
// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const;
// Adjust a data pointer to access a given array element, NULL if something goes bad
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE;
};
//===========================================================================
// Verilator DPI open array variable
class VerilatedDpiOpenVar final {
// MEMBERS
const VerilatedVarProps* const m_propsp; // Variable properties
void* const m_datap; // Location of data (local to thread always, so safe)
public:
// CONSTRUCTORS
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
: m_propsp{propsp}
, m_datap{datap} {}
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
: m_propsp{propsp}
, m_datap{const_cast<void*>(datap)} {}
~VerilatedDpiOpenVar() = default;
// METHODS
void* datap() const VL_MT_SAFE { return m_datap; }
// METHODS - from VerilatedVarProps
bool magicOk() const { return m_propsp->magicOk(); }
VerilatedVarType vltype() const { return m_propsp->vltype(); }
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
int entBits() const { return m_propsp->entBits(); }
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
int low(int dim) const { return m_propsp->low(dim); }
int high(int dim) const { return m_propsp->high(dim); }
int increment(int dim) const { return m_propsp->increment(dim); }
int elements(int dim) const { return m_propsp->elements(dim); }
size_t totalSize() const { return m_propsp->totalSize(); }
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
return m_propsp->datapAdjustIndex(datap, dim, indx);
}
};
//===========================================================================
// Verilator variable
// Thread safety: Assume is constructed only with model, then any number of readers
class VerilatedVar final : public VerilatedVarProps {
// MEMBERS
void* const m_datap; // Location of data
const char* const m_namep; // Name - slowpath
protected:
const bool m_isParam;
friend class VerilatedScope;
// CONSTRUCTORS
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam)
: VerilatedVarProps{vltype, vlflags, udims, pdims}
, m_datap{datap}
, m_namep{namep}
, m_isParam{isParam} {}
public:
~VerilatedVar() = default;
// ACCESSORS
void* datap() const { return m_datap; }
const char* name() const { return m_namep; }
bool isParam() const { return m_isParam; }
};
#endif // Guard