forked from github/verilator
256 lines
10 KiB
C++
256 lines
10 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
// Copyright 2003-2023 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
|
|
const int m_pdims; // Packed dimensions, 0 = none
|
|
const int m_udims; // Unpacked dimensions, 0 = none
|
|
VerilatedRange m_packed; // Packed array range
|
|
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
|
void initUnpacked(const int* ulims) {
|
|
for (int i = 0; i < m_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);
|
|
}
|
|
}
|
|
// CONSTRUCTORS
|
|
protected:
|
|
friend class VerilatedScope;
|
|
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
|
: m_magic{MAGIC}
|
|
, m_vltype{vltype}
|
|
, m_vlflags{vlflags}
|
|
, m_pdims{pdims}
|
|
, m_udims{udims} {
|
|
initUnpacked(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
|
|
, m_pdims{0}
|
|
, m_udims{0} {}
|
|
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
|
|
, m_pdims{0}
|
|
, m_udims{udims} {
|
|
initUnpacked(ulims);
|
|
}
|
|
// With packed
|
|
class Packed {};
|
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
|
: m_magic{MAGIC}
|
|
, m_vltype{vltype}
|
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
|
, m_pdims{1}
|
|
, m_udims{0}
|
|
, m_packed{pl, pr} {}
|
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
|
int udims, const int* ulims)
|
|
: m_magic{MAGIC}
|
|
, m_vltype{vltype}
|
|
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
|
, m_pdims{1}
|
|
, m_udims{udims}
|
|
, m_packed{pl, pr} {
|
|
initUnpacked(ulims);
|
|
}
|
|
|
|
~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;
|
|
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_udims; }
|
|
int dims() const { return m_pdims + m_udims; }
|
|
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
|
|
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
|
// DPI accessors
|
|
int left(int dim) const VL_MT_SAFE {
|
|
return dim == 0 ? m_packed.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_packed.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_packed.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_packed.high()
|
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
|
: 0;
|
|
}
|
|
int increment(int dim) const {
|
|
return dim == 0 ? m_packed.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_packed.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(); }
|
|
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
|
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
|
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 dims, bool isParam)
|
|
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
|
|
, m_datap{datap}
|
|
, m_namep{namep}
|
|
, m_isParam{isParam} {}
|
|
|
|
public:
|
|
~VerilatedVar() = default;
|
|
// ACCESSORS
|
|
void* datap() const { return m_datap; }
|
|
const VerilatedRange& range() const { return packed(); } // Deprecated
|
|
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
|
const char* name() const { return m_namep; }
|
|
bool isParam() const { return m_isParam; }
|
|
};
|
|
|
|
#endif // Guard
|