2025-09-27 14:19:57 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: AstNode attributes and sub-types
|
|
|
|
|
//
|
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2026-01-27 02:24:34 +01:00
|
|
|
// 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: 2003-2026 Wilson Snyder
|
2025-09-27 14:19:57 +02:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// This files contains small classes that contain attributes or enum classes
|
|
|
|
|
// used by V3AstNode*.h. Classes that are part of the base AST structure
|
|
|
|
|
// belong in V3Ast.h instead.
|
|
|
|
|
//
|
|
|
|
|
// The classes in this file should kept in mostly sorted order, with
|
|
|
|
|
// a few earlier-definition dependent exception at the end.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef VERILATOR_V3ASTATTR_H_
|
|
|
|
|
#define VERILATOR_V3ASTATTR_H_
|
|
|
|
|
|
|
|
|
|
#ifndef VERILATOR_V3AST_H_
|
|
|
|
|
#error "Use V3Ast.h as the include"
|
|
|
|
|
#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h
|
|
|
|
|
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Hint class so we can choose constructors
|
|
|
|
|
class VFlagBitPacked {};
|
|
|
|
|
class VFlagChildDType {}; // Used by parser.y to select constructor that sets childDType
|
|
|
|
|
class VFlagLogicPacked {};
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
2026-05-15 14:38:38 +02:00
|
|
|
class VAbortKind final {
|
|
|
|
|
public:
|
|
|
|
|
// IEEE 1800-2023 16.12.14 property abort operators.
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
ACCEPT_ON, // accept_on(cond) prop: async abort, property succeeds
|
|
|
|
|
REJECT_ON, // reject_on(cond) prop: async abort, property fails
|
|
|
|
|
SYNC_ACCEPT_ON, // sync_accept_on(cond) prop: sampled at matured clock, succeeds
|
|
|
|
|
SYNC_REJECT_ON // sync_reject_on(cond) prop: sampled at matured clock, fails
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAbortKind(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"accept_on", "reject_on", "sync_accept_on", "sync_reject_on"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool isAccept() const { return m_e == ACCEPT_ON || m_e == SYNC_ACCEPT_ON; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2025-09-27 14:19:57 +02:00
|
|
|
class VAccess final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
READ, // Read/Consumed, variable not changed
|
|
|
|
|
WRITE, // Written/Updated, variable might be updated, but not consumed
|
|
|
|
|
// // so variable might be removable if not consumed elsewhere
|
|
|
|
|
READWRITE, // Read/Consumed and written/updated, variable both set and
|
|
|
|
|
// // also consumed, cannot remove usage of variable.
|
|
|
|
|
// // For non-simple data types only e.g. no tristates/delayed vars.
|
|
|
|
|
NOCHANGE // No change to previous state, used only in V3LinkLValue
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"RD", "WR", "RW", "--"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* arrow() const {
|
|
|
|
|
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LRV] <=>", "--"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
VAccess()
|
|
|
|
|
: m_e{READ} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAccess(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAccess(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
VAccess invert() const {
|
|
|
|
|
return (m_e == READWRITE) ? VAccess{m_e} : (m_e == WRITE ? VAccess{READ} : VAccess{WRITE});
|
|
|
|
|
}
|
|
|
|
|
bool isReadOnly() const { return m_e == READ; } // False with READWRITE
|
|
|
|
|
bool isWriteOnly() const { return m_e == WRITE; } // False with READWRITE
|
|
|
|
|
bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
|
|
|
|
|
bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
|
|
|
|
|
bool isRW() const { return m_e == READWRITE; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; }
|
|
|
|
|
constexpr bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VAlwaysKwd final {
|
|
|
|
|
public:
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB, CONT_ASSIGN };
|
2025-09-27 14:19:57 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
VAlwaysKwd()
|
|
|
|
|
: m_e{ALWAYS} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAlwaysKwd(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAlwaysKwd(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
static const char* const names[]
|
|
|
|
|
= {"always", "always_ff", "always_latch", "always_comb", "cont_assign"};
|
2025-09-27 14:19:57 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VAssertCtlType final {
|
|
|
|
|
public:
|
|
|
|
|
// IEEE 1800-2023 Table 20-5
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
_TO_BE_EVALUATED = 0,
|
|
|
|
|
LOCK = 1,
|
|
|
|
|
UNLOCK = 2,
|
|
|
|
|
ON = 3,
|
|
|
|
|
OFF = 4,
|
|
|
|
|
KILL = 5,
|
|
|
|
|
PASS_ON = 6,
|
|
|
|
|
PASS_OFF = 7,
|
|
|
|
|
FAIL_ON = 8,
|
|
|
|
|
FAIL_OFF = 9,
|
|
|
|
|
NONVACUOUS_ON = 10,
|
|
|
|
|
VACUOUS_OFF = 11
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VAssertCtlType()
|
|
|
|
|
: m_e{_TO_BE_EVALUATED} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAssertCtlType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAssertCtlType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
// IEEE 1800-2023 20.11
|
|
|
|
|
static const char* const names[] = {"",
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
"$asserton",
|
|
|
|
|
"$assertoff",
|
|
|
|
|
"$assertkill",
|
|
|
|
|
"$assertpasson",
|
|
|
|
|
"$assertpassoff",
|
|
|
|
|
"$assertfailon",
|
|
|
|
|
"$assertfailoff",
|
|
|
|
|
"$assertnonvacuouson",
|
|
|
|
|
"$assertvacuousoff"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAssertCtlType& lhs, const VAssertCtlType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VAssertCtlType& lhs, VAssertCtlType::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VAssertCtlType::en lhs, const VAssertCtlType& rhs) {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VAssertDirectiveType final {
|
|
|
|
|
public:
|
|
|
|
|
// IEEE 1800-2023 Table 20-7
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
INTERNAL = 0, // Non IEEE type, for directives to be evaluated from expression.
|
|
|
|
|
ASSERT = (1 << 0),
|
|
|
|
|
COVER = (1 << 1),
|
|
|
|
|
ASSUME = (1 << 2),
|
|
|
|
|
VIOLATION_CASE = (1 << 3), // Non IEEE type, for case constructs
|
|
|
|
|
// with unique, unique0 or priority pragmas.
|
|
|
|
|
VIOLATION_IF = (1 << 4), // Non IEEE type, for if constructs
|
|
|
|
|
// with unique, unique0 or priority pragmas.
|
|
|
|
|
INTRINSIC = (1 << 5), // Non IEEE type, for intrinsic assertions.
|
|
|
|
|
RESTRICT = (1 << 6), // Non IEEE type, for ignored restrict assertions.
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VAssertDirectiveType()
|
|
|
|
|
: m_e{ASSERT} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAssertDirectiveType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAssertDirectiveType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2025-10-02 18:03:45 +02:00
|
|
|
string ascii() const {
|
|
|
|
|
std::stringstream types;
|
|
|
|
|
if (m_e == INTERNAL)
|
|
|
|
|
types << "INTERNAL ";
|
|
|
|
|
else {
|
|
|
|
|
if (m_e & ASSERT) types << "ASSERT ";
|
|
|
|
|
if (m_e & COVER) types << "COVER ";
|
|
|
|
|
if (m_e & ASSUME) types << "ASSUME ";
|
|
|
|
|
if (m_e & VIOLATION_CASE) types << "VIOLATION_CASE ";
|
|
|
|
|
if (m_e & VIOLATION_IF) types << "VIOLATION_IF ";
|
|
|
|
|
if (m_e & INTRINSIC) types << "INTRINSIC ";
|
|
|
|
|
if (m_e & RESTRICT) types << "RESTRICT ";
|
|
|
|
|
}
|
|
|
|
|
const string str = types.str();
|
|
|
|
|
UASSERT(!str.empty(), "Assert should be of one of types");
|
|
|
|
|
return str.substr(0, str.size() - 1);
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAssertDirectiveType& lhs, const VAssertDirectiveType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VAssertDirectiveType& lhs, VAssertDirectiveType::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VAssertDirectiveType::en lhs, const VAssertDirectiveType& rhs) {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr VAssertDirectiveType::en operator|(VAssertDirectiveType::en lhs,
|
|
|
|
|
VAssertDirectiveType::en rhs) {
|
|
|
|
|
return VAssertDirectiveType::en(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VAssertType final {
|
|
|
|
|
public:
|
|
|
|
|
// IEEE 1800-2023 Table 20-6
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
INTERNAL = 0, // Non IEEE type, for assertions that should not be controlled.
|
|
|
|
|
CONCURRENT = (1 << 0),
|
|
|
|
|
SIMPLE_IMMEDIATE = (1 << 1),
|
|
|
|
|
OBSERVED_DEFERRED_IMMEDIATE = (1 << 2),
|
|
|
|
|
FINAL_DEFERRED_IMMEDIATE = (1 << 3),
|
|
|
|
|
EXPECT = (1 << 4),
|
|
|
|
|
UNIQUE = (1 << 5),
|
|
|
|
|
UNIQUE0 = (1 << 6),
|
|
|
|
|
PRIORITY = (1 << 7),
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VAssertType()
|
|
|
|
|
: m_e{INTERNAL} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAssertType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAssertType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
bool containsAny(VAssertType other) const { return m_e & other.m_e; }
|
2025-10-02 18:03:45 +02:00
|
|
|
string ascii() const {
|
|
|
|
|
std::stringstream types;
|
|
|
|
|
if (m_e == INTERNAL)
|
|
|
|
|
types << "INTERNAL ";
|
|
|
|
|
else {
|
|
|
|
|
if (m_e & CONCURRENT) types << "CONCURRENT ";
|
|
|
|
|
if (m_e & SIMPLE_IMMEDIATE) types << "SIMPLE_IMMEDIATE ";
|
|
|
|
|
if (m_e & OBSERVED_DEFERRED_IMMEDIATE) types << "OBSERVED_DEFERRED_IMMEDIATE ";
|
|
|
|
|
if (m_e & FINAL_DEFERRED_IMMEDIATE) types << "FINAL_DEFERRED_IMMEDIATE ";
|
|
|
|
|
if (m_e & EXPECT) types << "EXPECT ";
|
|
|
|
|
if (m_e & UNIQUE) types << "UNIQUE ";
|
|
|
|
|
if (m_e & UNIQUE0) types << "UNIQUE0 ";
|
|
|
|
|
if (m_e & PRIORITY) types << "PRIORITY ";
|
|
|
|
|
}
|
|
|
|
|
const string str = types.str();
|
|
|
|
|
UASSERT(!str.empty(), "Assert should be of one of types");
|
|
|
|
|
return str.substr(0, str.size() - 1);
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAssertType& lhs, const VAssertType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VAssertType& lhs, VAssertType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VAssertType::en lhs, const VAssertType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
constexpr VAssertType::en operator|(VAssertType::en lhs, VAssertType::en rhs) {
|
|
|
|
|
return VAssertType::en(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VAttrType final {
|
|
|
|
|
public:
|
|
|
|
|
// clang-format off
|
|
|
|
|
enum en: uint8_t {
|
|
|
|
|
ILLEGAL,
|
|
|
|
|
//
|
|
|
|
|
DIM_BITS, // V3Const converts to constant
|
|
|
|
|
DIM_BITS_OR_NUMBER, // V3Const converts to constant
|
|
|
|
|
DIM_DIMENSIONS, // V3Width converts to constant
|
|
|
|
|
DIM_HIGH, // V3Width processes
|
|
|
|
|
DIM_INCREMENT, // V3Width processes
|
|
|
|
|
DIM_LEFT, // V3Width processes
|
|
|
|
|
DIM_LOW, // V3Width processes
|
|
|
|
|
DIM_RIGHT, // V3Width processes
|
|
|
|
|
DIM_SIZE, // V3Width processes
|
|
|
|
|
DIM_UNPK_DIMENSIONS, // V3Width converts to constant
|
|
|
|
|
//
|
|
|
|
|
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
|
|
|
|
|
//
|
|
|
|
|
ENUM_FIRST, // V3Width processes
|
|
|
|
|
ENUM_LAST, // V3Width processes
|
|
|
|
|
ENUM_NUM, // V3Width processes
|
|
|
|
|
ENUM_NEXT, // V3Width processes
|
|
|
|
|
ENUM_PREV, // V3Width processes
|
|
|
|
|
ENUM_NAME, // V3Width processes
|
|
|
|
|
ENUM_VALID, // V3Width processes
|
|
|
|
|
//
|
|
|
|
|
FUNC_ARG_PROTO, // V3WidthCommit processes
|
|
|
|
|
FUNC_RETURN_PROTO, // V3WidthCommit processes
|
|
|
|
|
//
|
|
|
|
|
TYPEID, // V3Width processes
|
|
|
|
|
TYPENAME, // V3Width processes
|
|
|
|
|
//
|
|
|
|
|
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
|
|
|
|
VAR_FORCEABLE, // V3LinkParse moves to AstVar::isForceable
|
2026-04-22 21:18:59 +02:00
|
|
|
VAR_FSM_ARC_INCLUDE_COND, // V3LinkParse moves to AstVar::attrFsmArcInclCond
|
|
|
|
|
VAR_FSM_RESET_ARC, // V3LinkParse moves to AstVar::attrFsmResetArc
|
|
|
|
|
VAR_FSM_STATE, // V3LinkParse moves to AstVar::attrFsmState
|
2025-09-27 14:19:57 +02:00
|
|
|
VAR_PORT_DTYPE, // V3LinkDot for V3Width to check port dtype
|
|
|
|
|
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
|
|
|
|
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
|
|
|
|
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
|
|
|
|
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
2025-11-20 23:08:59 +01:00
|
|
|
VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint
|
2025-09-27 14:19:57 +02:00
|
|
|
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
|
|
|
|
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
|
|
|
|
VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar
|
|
|
|
|
};
|
|
|
|
|
// clang-format on
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
// clang-format off
|
|
|
|
|
static const char* const names[] = {
|
|
|
|
|
"%E-AT",
|
|
|
|
|
"DIM_BITS", "DIM_BITS_OR_NUMBER", "DIM_DIMENSIONS",
|
|
|
|
|
"DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
|
|
|
|
|
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
|
|
|
|
|
"DT_PUBLIC",
|
|
|
|
|
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
|
|
|
|
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
|
|
|
|
|
"FUNC_ARG_PROTO", "FUNC_RETURN_PROTO",
|
|
|
|
|
"TYPEID", "TYPENAME",
|
2026-04-22 21:18:59 +02:00
|
|
|
"VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC",
|
|
|
|
|
"VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
2026-06-13 20:40:29 +02:00
|
|
|
"VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
2026-04-22 21:18:59 +02:00
|
|
|
"VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR"
|
2025-09-27 14:19:57 +02:00
|
|
|
};
|
|
|
|
|
// clang-format on
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2026-06-06 17:55:47 +02:00
|
|
|
// True for attributes that read an operand's type rather than its value, such as $bits.
|
|
|
|
|
bool isTypeQuery() const {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case DIM_BITS:
|
|
|
|
|
case DIM_BITS_OR_NUMBER:
|
|
|
|
|
case DIM_DIMENSIONS:
|
|
|
|
|
case DIM_HIGH:
|
|
|
|
|
case DIM_INCREMENT:
|
|
|
|
|
case DIM_LEFT:
|
|
|
|
|
case DIM_LOW:
|
|
|
|
|
case DIM_RIGHT:
|
|
|
|
|
case DIM_SIZE:
|
|
|
|
|
case DIM_UNPK_DIMENSIONS:
|
|
|
|
|
case TYPEID:
|
|
|
|
|
case TYPENAME: return true;
|
|
|
|
|
default: return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-27 14:19:57 +02:00
|
|
|
VAttrType()
|
|
|
|
|
: m_e{ILLEGAL} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VAttrType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VAttrType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VAttrType& lhs, const VAttrType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VAttrType& lhs, VAttrType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VAttrType::en lhs, const VAttrType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VBaseOverride final {
|
|
|
|
|
bool m_extends : 1;
|
|
|
|
|
bool m_final : 1;
|
|
|
|
|
bool m_initial : 1;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
VBaseOverride()
|
|
|
|
|
: m_extends{false}
|
|
|
|
|
, m_final{false}
|
|
|
|
|
, m_initial{false} {}
|
|
|
|
|
class Extends {};
|
|
|
|
|
explicit VBaseOverride(Extends)
|
|
|
|
|
: m_extends{true}
|
|
|
|
|
, m_final{false}
|
|
|
|
|
, m_initial{false} {}
|
|
|
|
|
class Final {};
|
|
|
|
|
explicit VBaseOverride(Final)
|
|
|
|
|
: m_extends{false}
|
|
|
|
|
, m_final{true}
|
|
|
|
|
, m_initial{false} {}
|
|
|
|
|
class Initial {};
|
|
|
|
|
explicit VBaseOverride(Initial)
|
|
|
|
|
: m_extends{false}
|
|
|
|
|
, m_final{false}
|
|
|
|
|
, m_initial{true} {}
|
|
|
|
|
void combine(const VBaseOverride& other) {
|
|
|
|
|
m_extends |= other.m_extends;
|
|
|
|
|
m_final |= other.m_final;
|
|
|
|
|
m_initial |= other.m_initial;
|
|
|
|
|
}
|
|
|
|
|
bool isAny() const { return m_extends | m_final | m_initial; }
|
|
|
|
|
bool isExtends() const { return m_extends; }
|
|
|
|
|
bool isFinal() const { return m_final; }
|
|
|
|
|
bool isInitial() const { return m_initial; }
|
|
|
|
|
string ascii() const {
|
|
|
|
|
string out;
|
|
|
|
|
if (m_initial) out = VString::dot(out, " ", "initial");
|
|
|
|
|
if (m_extends) out = VString::dot(out, " ", "extends");
|
|
|
|
|
if (m_final) out = VString::dot(out, " ", "final");
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VBasicDTypeKwd final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
UNKNOWN,
|
|
|
|
|
BIT,
|
|
|
|
|
BYTE,
|
|
|
|
|
CHANDLE,
|
2026-01-17 20:15:52 +01:00
|
|
|
// Void type for tagged union members (CVOID to avoid Windows VOID macro)
|
|
|
|
|
CVOID,
|
2025-09-27 14:19:57 +02:00
|
|
|
EVENT,
|
|
|
|
|
INT,
|
|
|
|
|
INTEGER,
|
|
|
|
|
LOGIC,
|
|
|
|
|
LONGINT,
|
|
|
|
|
DOUBLE,
|
|
|
|
|
SHORTINT,
|
|
|
|
|
TIME,
|
|
|
|
|
// Closer to a class type, but limited usage
|
|
|
|
|
STRING,
|
|
|
|
|
// Property / Sequence argument type
|
|
|
|
|
UNTYPED,
|
|
|
|
|
// Internal types for mid-steps
|
|
|
|
|
SCOPEPTR,
|
|
|
|
|
CHARPTR,
|
|
|
|
|
MTASKSTATE,
|
|
|
|
|
DELAY_SCHEDULER,
|
|
|
|
|
TRIGGER_SCHEDULER,
|
|
|
|
|
DYNAMIC_TRIGGER_SCHEDULER,
|
|
|
|
|
FORK_SYNC,
|
|
|
|
|
PROCESS_REFERENCE,
|
|
|
|
|
RANDOM_GENERATOR,
|
|
|
|
|
RANDOM_STDGENERATOR,
|
|
|
|
|
// Unsigned and two state; fundamental types
|
|
|
|
|
UINT32,
|
|
|
|
|
UINT64,
|
|
|
|
|
// Internal types, eliminated after parsing
|
|
|
|
|
LOGIC_IMPLICIT,
|
|
|
|
|
// Leave last
|
|
|
|
|
_ENUM_MAX
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const VL_MT_SAFE {
|
|
|
|
|
static const char* const names[] = {"%E-unk",
|
|
|
|
|
"bit",
|
|
|
|
|
"byte",
|
|
|
|
|
"chandle",
|
2026-01-17 20:15:52 +01:00
|
|
|
"void",
|
2025-09-27 14:19:57 +02:00
|
|
|
"event",
|
|
|
|
|
"int",
|
|
|
|
|
"integer",
|
|
|
|
|
"logic",
|
|
|
|
|
"longint",
|
|
|
|
|
"real",
|
|
|
|
|
"shortint",
|
|
|
|
|
"time",
|
|
|
|
|
"string",
|
|
|
|
|
"untyped",
|
|
|
|
|
"VerilatedScope*",
|
|
|
|
|
"char*",
|
|
|
|
|
"VlMTaskState",
|
|
|
|
|
"VlDelayScheduler",
|
|
|
|
|
"VlTriggerScheduler",
|
|
|
|
|
"VlDynamicTriggerScheduler",
|
|
|
|
|
"VlFork",
|
|
|
|
|
"VlProcessRef",
|
|
|
|
|
"VlRandomizer",
|
|
|
|
|
"VlStdRandomizer",
|
|
|
|
|
"IData",
|
|
|
|
|
"QData",
|
|
|
|
|
"LOGIC_IMPLICIT",
|
|
|
|
|
" MAX"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* dpiType() const {
|
2026-01-17 20:15:52 +01:00
|
|
|
static const char* const names[] = {"%E-unk",
|
|
|
|
|
"svBit",
|
|
|
|
|
"char",
|
|
|
|
|
"void*",
|
|
|
|
|
"void",
|
|
|
|
|
"char",
|
|
|
|
|
"int",
|
|
|
|
|
"%E-integer",
|
|
|
|
|
"svLogic",
|
|
|
|
|
"long long",
|
|
|
|
|
"double",
|
|
|
|
|
"short",
|
|
|
|
|
"%E-time",
|
|
|
|
|
"const char*",
|
|
|
|
|
"%E-untyped",
|
|
|
|
|
"dpiScope",
|
|
|
|
|
"const char*",
|
|
|
|
|
"%E-mtaskstate",
|
|
|
|
|
"%E-dly-sched",
|
|
|
|
|
"%E-trig-sched",
|
|
|
|
|
"%E-dyn-sched",
|
|
|
|
|
"%E-fork",
|
|
|
|
|
"%E-proc-ref",
|
|
|
|
|
"%E-rand-gen",
|
|
|
|
|
"%E-stdrand-gen",
|
|
|
|
|
"IData",
|
|
|
|
|
"QData",
|
|
|
|
|
"%E-logic-implct",
|
|
|
|
|
" MAX"};
|
2025-09-27 14:19:57 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
static void selfTest() {
|
|
|
|
|
UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.ascii(), " MAX"),
|
|
|
|
|
"SelfTest: Enum mismatch");
|
|
|
|
|
UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.dpiType(), " MAX"),
|
|
|
|
|
"SelfTest: Enum mismatch");
|
|
|
|
|
}
|
|
|
|
|
VBasicDTypeKwd()
|
|
|
|
|
: m_e{UNKNOWN} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VBasicDTypeKwd(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VBasicDTypeKwd(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
int width() const {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case BIT: return 1; // scalar, can't bit extract unless ranged
|
|
|
|
|
case BYTE: return 8;
|
|
|
|
|
case CHANDLE: return 64;
|
|
|
|
|
case EVENT: return 1;
|
|
|
|
|
case INT: return 32;
|
|
|
|
|
case INTEGER: return 32;
|
|
|
|
|
case LOGIC: return 1; // scalar, can't bit extract unless ranged
|
|
|
|
|
case LONGINT: return 64;
|
|
|
|
|
case DOUBLE: return 64; // opaque
|
|
|
|
|
case SHORTINT: return 16;
|
|
|
|
|
case TIME: return 64;
|
|
|
|
|
case STRING: return 64; // opaque // Just the pointer, for today
|
|
|
|
|
case SCOPEPTR: return 0; // opaque
|
|
|
|
|
case CHARPTR: return 0; // opaque
|
|
|
|
|
case MTASKSTATE: return 0; // opaque
|
|
|
|
|
case DELAY_SCHEDULER: return 0; // opaque
|
|
|
|
|
case TRIGGER_SCHEDULER: return 0; // opaque
|
|
|
|
|
case DYNAMIC_TRIGGER_SCHEDULER: return 0; // opaque
|
|
|
|
|
case FORK_SYNC: return 0; // opaque
|
|
|
|
|
case PROCESS_REFERENCE: return 0; // opaque
|
|
|
|
|
case RANDOM_GENERATOR: return 0; // opaque
|
|
|
|
|
case RANDOM_STDGENERATOR: return 0; // opaque
|
|
|
|
|
case UINT32: return 32;
|
|
|
|
|
case UINT64: return 64;
|
|
|
|
|
default: return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool isSigned() const {
|
|
|
|
|
return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER
|
|
|
|
|
|| m_e == DOUBLE;
|
|
|
|
|
}
|
|
|
|
|
bool isUnsigned() const {
|
|
|
|
|
return m_e == CHANDLE || m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|
|
|
|
|
|| m_e == UINT32 || m_e == UINT64 || m_e == BIT || m_e == LOGIC || m_e == TIME;
|
|
|
|
|
}
|
|
|
|
|
bool isFourstate() const {
|
|
|
|
|
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
|
|
|
|
|
}
|
|
|
|
|
bool isZeroInit() const { // Otherwise initializes to X
|
|
|
|
|
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENT || m_e == INT
|
|
|
|
|
|| m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE);
|
|
|
|
|
}
|
|
|
|
|
bool isIntNumeric() const { // Enum increment supported
|
|
|
|
|
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|
|
|
|
|
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64
|
|
|
|
|
|| m_e == TIME);
|
|
|
|
|
}
|
2026-03-05 14:37:20 +01:00
|
|
|
bool isBit() const { return m_e == BIT; }
|
2025-09-27 14:19:57 +02:00
|
|
|
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
|
|
|
|
|
return (m_e == LOGIC || m_e == BIT);
|
|
|
|
|
}
|
|
|
|
|
bool isDpiUnsignable() const { // Can add "unsigned" to DPI
|
|
|
|
|
return (m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER);
|
|
|
|
|
}
|
|
|
|
|
bool isDpiCLayout() const { // Uses standard C layout, for DPI runtime access
|
|
|
|
|
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT
|
|
|
|
|
|| m_e == DOUBLE || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
|
|
|
|
|
}
|
|
|
|
|
bool isOpaque() const VL_MT_SAFE { // IE not a simple number we can bit optimize
|
|
|
|
|
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|
2025-10-31 19:29:11 +01:00
|
|
|
|| m_e == MTASKSTATE || m_e == DELAY_SCHEDULER || m_e == TRIGGER_SCHEDULER
|
|
|
|
|
|| m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC || m_e == PROCESS_REFERENCE
|
|
|
|
|
|| m_e == RANDOM_GENERATOR || m_e == RANDOM_STDGENERATOR || m_e == DOUBLE
|
|
|
|
|
|| m_e == UNTYPED);
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
2026-02-17 11:39:39 +01:00
|
|
|
bool isCHandle() const VL_MT_SAFE { return m_e == CHANDLE; }
|
2025-09-27 14:19:57 +02:00
|
|
|
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
|
|
|
|
|
bool isEvent() const { return m_e == EVENT; }
|
|
|
|
|
bool isString() const VL_MT_SAFE { return m_e == STRING; }
|
|
|
|
|
bool isMTaskState() const VL_MT_SAFE { return m_e == MTASKSTATE; }
|
|
|
|
|
// Does this represent a C++ LiteralType? (can be constexpr)
|
|
|
|
|
bool isLiteralType() const VL_MT_SAFE {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case BIT:
|
|
|
|
|
case BYTE:
|
|
|
|
|
case CHANDLE:
|
|
|
|
|
case INT:
|
|
|
|
|
case INTEGER:
|
|
|
|
|
case LOGIC:
|
|
|
|
|
case LONGINT:
|
|
|
|
|
case DOUBLE:
|
|
|
|
|
case SHORTINT:
|
|
|
|
|
case SCOPEPTR:
|
|
|
|
|
case CHARPTR:
|
|
|
|
|
case UINT32:
|
|
|
|
|
case UINT64: return true;
|
|
|
|
|
default: return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* traceSigType() const {
|
|
|
|
|
// VerilatedTraceSigType to used in trace signal declaration
|
|
|
|
|
static const char* const lut[] = {
|
|
|
|
|
/* UNKNOWN: */ "", // Should not be traced
|
|
|
|
|
/* BIT: */ "BIT",
|
|
|
|
|
/* BYTE: */ "BYTE",
|
|
|
|
|
/* CHANDLE: */ "LONGINT",
|
2026-01-17 20:15:52 +01:00
|
|
|
/* CVOID: */ "", // Should not be traced
|
2025-09-27 14:19:57 +02:00
|
|
|
/* EVENT: */ "EVENT",
|
|
|
|
|
/* INT: */ "INT",
|
|
|
|
|
/* INTEGER: */ "INTEGER",
|
|
|
|
|
/* LOGIC: */ "LOGIC",
|
|
|
|
|
/* LONGINT: */ "LONGINT",
|
|
|
|
|
/* DOUBLE: */ "DOUBLE",
|
|
|
|
|
/* SHORTINT: */ "SHORTINT",
|
|
|
|
|
/* TIME: */ "TIME",
|
|
|
|
|
/* STRING: */ "",
|
|
|
|
|
/* UNTYPED: */ "", // Should not be traced
|
|
|
|
|
/* SCOPEPTR: */ "", // Should not be traced
|
|
|
|
|
/* CHARPTR: */ "", // Should not be traced
|
|
|
|
|
/* MTASKSTATE: */ "", // Should not be traced
|
|
|
|
|
/* DELAY_SCHEDULER: */ "", // Should not be traced
|
|
|
|
|
/* TRIGGER_SCHEDULER: */ "", // Should not be traced
|
|
|
|
|
/* DYNAMIC_TRIGGER_SCHEDULER: */ "", // Should not be traced
|
|
|
|
|
/* FORK_SYNC: */ "", // Should not be traced
|
|
|
|
|
/* PROCESS_REFERENCE: */ "", // Should not be traced
|
|
|
|
|
/* RANDOM_GENERATOR: */ "", // Should not be traced
|
|
|
|
|
/* RANDOM_STD_GENERATOR: */ "", // Should not be traced
|
|
|
|
|
/* UINT32: */ "BIT",
|
|
|
|
|
/* UINT64: */ "BIT",
|
|
|
|
|
/* LOGIC_IMPLICIT: */ "", // Should not be traced
|
|
|
|
|
};
|
|
|
|
|
return lut[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VBasicDTypeKwd& lhs, VBasicDTypeKwd::en rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VBasicDTypeKwd::en lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
/// Boolean or unknown
|
|
|
|
|
class VBoolOrUnknown final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
|
|
|
|
VBoolOrUnknown()
|
|
|
|
|
: m_e{BU_UNKNOWN} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VBoolOrUnknown(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VBoolOrUnknown(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"FALSE", "TRUE", "UNK"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool trueKnown() const { return m_e == BU_TRUE; }
|
|
|
|
|
void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VBranchPred final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
|
|
|
|
VBranchPred()
|
|
|
|
|
: m_e{BP_UNKNOWN} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VBranchPred(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VBranchPred(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
bool unknown() const { return m_e == BP_UNKNOWN; }
|
|
|
|
|
bool likely() const { return m_e == BP_LIKELY; }
|
|
|
|
|
bool unlikely() const { return m_e == BP_UNLIKELY; }
|
|
|
|
|
VBranchPred invert() const {
|
2026-03-28 04:14:18 +01:00
|
|
|
if (m_e == BP_UNLIKELY) return BP_LIKELY;
|
|
|
|
|
if (m_e == BP_LIKELY) return BP_UNLIKELY;
|
|
|
|
|
return m_e;
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"", "VL_LIKELY", "VL_UNLIKELY"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
2025-09-27 14:22:17 +02:00
|
|
|
|
|
|
|
|
class VCMethod final {
|
|
|
|
|
public:
|
|
|
|
|
// Entries in this table need to match below VCMethod::s_itemData[] table
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
_NONE, // Unknown
|
|
|
|
|
ARRAY_AND,
|
|
|
|
|
ARRAY_AT,
|
|
|
|
|
ARRAY_AT_BACK,
|
|
|
|
|
ARRAY_AT_WRITE,
|
|
|
|
|
ARRAY_FIND,
|
|
|
|
|
ARRAY_FIND_FIRST,
|
|
|
|
|
ARRAY_FIND_FIRST_INDEX,
|
|
|
|
|
ARRAY_FIND_INDEX,
|
|
|
|
|
ARRAY_FIND_LAST,
|
|
|
|
|
ARRAY_FIND_LAST_INDEX,
|
|
|
|
|
ARRAY_FIRST,
|
|
|
|
|
ARRAY_INSIDE,
|
|
|
|
|
ARRAY_LAST,
|
2026-03-24 10:38:50 +01:00
|
|
|
ARRAY_MAP,
|
2025-09-27 14:22:17 +02:00
|
|
|
ARRAY_MAX,
|
|
|
|
|
ARRAY_MIN,
|
|
|
|
|
ARRAY_NEXT,
|
|
|
|
|
ARRAY_OR,
|
|
|
|
|
ARRAY_POP_BACK,
|
|
|
|
|
ARRAY_POP_FRONT,
|
|
|
|
|
ARRAY_PREV,
|
|
|
|
|
ARRAY_PRODUCT,
|
|
|
|
|
ARRAY_PUSH_BACK,
|
|
|
|
|
ARRAY_PUSH_FRONT,
|
|
|
|
|
ARRAY_REVERSE,
|
|
|
|
|
ARRAY_RSORT,
|
|
|
|
|
ARRAY_R_AND,
|
|
|
|
|
ARRAY_R_OR,
|
|
|
|
|
ARRAY_R_PRODUCT,
|
|
|
|
|
ARRAY_R_SUM,
|
|
|
|
|
ARRAY_R_XOR,
|
|
|
|
|
ARRAY_SHUFFLE,
|
|
|
|
|
ARRAY_SORT,
|
|
|
|
|
ARRAY_SUM,
|
|
|
|
|
ARRAY_UNIQUE,
|
|
|
|
|
ARRAY_UNIQUE_INDEX,
|
|
|
|
|
ARRAY_XOR,
|
|
|
|
|
ASSOC_CLEAR,
|
|
|
|
|
ASSOC_ERASE,
|
|
|
|
|
ASSOC_EXISTS,
|
|
|
|
|
ASSOC_FIRST,
|
|
|
|
|
ASSOC_NEXT,
|
|
|
|
|
ASSOC_SIZE,
|
|
|
|
|
CLASS_SET_RANDMODE,
|
|
|
|
|
DYN_AT_WRITE_APPEND,
|
|
|
|
|
DYN_AT_WRITE_APPEND_BACK,
|
|
|
|
|
DYN_CLEAR,
|
|
|
|
|
DYN_ERASE,
|
|
|
|
|
DYN_INSERT,
|
|
|
|
|
DYN_POP,
|
|
|
|
|
DYN_POP_FRONT,
|
|
|
|
|
DYN_PUSH,
|
|
|
|
|
DYN_PUSH_FRONT,
|
|
|
|
|
DYN_RENEW,
|
|
|
|
|
DYN_RENEW_COPY,
|
|
|
|
|
DYN_RESIZE,
|
|
|
|
|
DYN_SIZE,
|
|
|
|
|
DYN_SLICE,
|
2026-03-17 20:10:49 +01:00
|
|
|
DYN_SLICE_ASSIGN,
|
|
|
|
|
DYN_SLICE_ASSIGN_BACK_BACK,
|
|
|
|
|
DYN_SLICE_ASSIGN_FRONT_BACK,
|
2025-09-27 14:22:17 +02:00
|
|
|
DYN_SLICE_BACK_BACK,
|
|
|
|
|
DYN_SLICE_FRONT_BACK,
|
|
|
|
|
EVENT_CLEAR_FIRED,
|
|
|
|
|
EVENT_CLEAR_TRIGGERED,
|
|
|
|
|
EVENT_FIRE,
|
|
|
|
|
EVENT_IS_FIRED,
|
|
|
|
|
EVENT_IS_TRIGGERED,
|
2026-04-21 17:54:42 +02:00
|
|
|
FORCE_ADD,
|
|
|
|
|
FORCE_READ,
|
|
|
|
|
FORCE_READ_INDEX,
|
2026-05-14 13:38:42 +02:00
|
|
|
FORCE_READ_SEL,
|
2026-04-21 17:54:42 +02:00
|
|
|
FORCE_RELEASE,
|
|
|
|
|
FORCE_TOUCH,
|
2025-09-27 14:22:17 +02:00
|
|
|
FORK_DONE,
|
|
|
|
|
FORK_INIT,
|
|
|
|
|
FORK_JOIN,
|
2026-03-24 03:56:31 +01:00
|
|
|
FORK_ON_KILL,
|
2025-09-27 14:22:17 +02:00
|
|
|
RANDOMIZER_BASIC_STD_RANDOMIZATION,
|
2025-11-14 20:32:01 +01:00
|
|
|
RANDOMIZER_CLEARCONSTRAINTS,
|
|
|
|
|
RANDOMIZER_CLEARALL,
|
2026-03-03 17:23:14 +01:00
|
|
|
RANDOMIZER_DISABLE_SOFT,
|
2025-09-27 14:22:17 +02:00
|
|
|
RANDOMIZER_HARD,
|
2026-03-01 21:16:55 +01:00
|
|
|
RANDOMIZER_SOFT,
|
2026-01-16 14:42:09 +01:00
|
|
|
RANDOMIZER_UNIQUE,
|
2026-02-12 16:58:04 +01:00
|
|
|
RANDOMIZER_MARK_RANDC,
|
2026-02-22 17:33:18 +01:00
|
|
|
RANDOMIZER_SOLVE_BEFORE,
|
2026-03-11 11:51:32 +01:00
|
|
|
RANDOMIZER_PIN_VAR,
|
2025-09-27 14:22:17 +02:00
|
|
|
RANDOMIZER_WRITE_VAR,
|
2026-03-17 20:09:14 +01:00
|
|
|
RANDOMIZER_SET_VAR_DISABLED,
|
|
|
|
|
RANDOMIZER_CLEAR_VAR_DISABLED,
|
2026-04-29 23:07:27 +02:00
|
|
|
RANDOMIZER_MARK_VAR_STATIC,
|
|
|
|
|
RANDOMIZER_SET_STATIC_RANDMODE,
|
2025-09-27 14:22:17 +02:00
|
|
|
RNG_GET_RANDSTATE,
|
|
|
|
|
RNG_SET_RANDSTATE,
|
|
|
|
|
SCHED_ANY_TRIGGERED,
|
|
|
|
|
SCHED_AWAITING_CURRENT_TIME,
|
Support #0 delays with IEEE-1800 compliant semantics (#7079)
This patch adds IEEE-1800 compliant scheduling support for the Inactive
scheduling region used for #0 delays.
Implementing this requires that **all** IEEE-1800 active region events
are placed in the internal 'act' section. This has simulation
performance implications. It prevents some optimizations (e.g.
V3LifePost), which reduces single threaded performance. It also reduces
the available work and parallelism in the internal 'nba' section, which
reduced the effectiveness of multi-threading severely.
Performance impact on RTLMeter when using scheduling adjusted to support
proper #0 delays is ~10-20% slowdown in single-threaded mode, and ~100%
(2x slower) with --threads 4.
To avoid paying this performance penalty unconditionally, the scheduling
is only adjusted if either:
1. The input contains a statically known #0 delay
2. The input contains a variable #x delay unknown at compile time
If no #0 is present, but #x variable delays are, a ZERODLY warning is
issued advising the use of '--no-sched-zero-delay' which is a promise
by the user that none of the variable delays will evaluate to a zero
delay at run-time. This warning is turned off if '--sched-zero-delay'
is explicitly given. This is similar to the '--timing' option.
If '--no-sched-zero-delay' was used at compile time, then executing
a zero delay will fail at runtime.
A ZERODLY warning is also issued if a static #0 if found, but the user
specified '--no-sched-zero-delay'. In this case the scheduling is not
adjusted to support #0, so executing it will fail at runtime. Presumably
the user knows it won't be executed.
The intended behaviour with all this is the following:
No #0, no #var in the design (#constant is OK)
-> Same as current behaviour, scheduling not adjusted,
same code generated as before
Has static #0 and '--no-sched-zero-delay' is NOT given:
-> No warnings, scheduling adjusted so it just works, runs slow
Has static #0 and '--no-sched-zero-delay' is given:
-> ZERODLY on the #0, scheduling not adjusted, fails at runtime if hit
No static #0, but has #var and no option is given:
-> ZERODLY on the #var advising use of '--no-sched-zero-delay' or
'--sched-zero-delay' (similar to '--timing'), scheduling adjusted
assuming it can be a zero delay and it just works
No static #0, but has #var and '--no-sched-zero-delay' is given:
-> No warning, scheduling not adjusted, fails at runtime if zero delay
No static #0, but has #var and '--sched-zero-delay' is given:
-> No warning, scheduling adjusted so it just works
2026-02-16 04:55:55 +01:00
|
|
|
SCHED_AWAITING_ZERO_DELAY,
|
2026-02-11 19:35:59 +01:00
|
|
|
SCHED_READY,
|
2025-09-27 14:22:17 +02:00
|
|
|
SCHED_COMMIT,
|
2026-02-11 19:35:59 +01:00
|
|
|
SCHED_MOVE_TO_RESUME_QUEUE,
|
2025-09-27 14:22:17 +02:00
|
|
|
SCHED_DELAY,
|
|
|
|
|
SCHED_DO_POST_UPDATES,
|
|
|
|
|
SCHED_ENQUEUE,
|
|
|
|
|
SCHED_EVALUATE,
|
|
|
|
|
SCHED_EVALUATION,
|
|
|
|
|
SCHED_POST_UPDATE,
|
|
|
|
|
SCHED_RESUME,
|
Support #0 delays with IEEE-1800 compliant semantics (#7079)
This patch adds IEEE-1800 compliant scheduling support for the Inactive
scheduling region used for #0 delays.
Implementing this requires that **all** IEEE-1800 active region events
are placed in the internal 'act' section. This has simulation
performance implications. It prevents some optimizations (e.g.
V3LifePost), which reduces single threaded performance. It also reduces
the available work and parallelism in the internal 'nba' section, which
reduced the effectiveness of multi-threading severely.
Performance impact on RTLMeter when using scheduling adjusted to support
proper #0 delays is ~10-20% slowdown in single-threaded mode, and ~100%
(2x slower) with --threads 4.
To avoid paying this performance penalty unconditionally, the scheduling
is only adjusted if either:
1. The input contains a statically known #0 delay
2. The input contains a variable #x delay unknown at compile time
If no #0 is present, but #x variable delays are, a ZERODLY warning is
issued advising the use of '--no-sched-zero-delay' which is a promise
by the user that none of the variable delays will evaluate to a zero
delay at run-time. This warning is turned off if '--sched-zero-delay'
is explicitly given. This is similar to the '--timing' option.
If '--no-sched-zero-delay' was used at compile time, then executing
a zero delay will fail at runtime.
A ZERODLY warning is also issued if a static #0 if found, but the user
specified '--no-sched-zero-delay'. In this case the scheduling is not
adjusted to support #0, so executing it will fail at runtime. Presumably
the user knows it won't be executed.
The intended behaviour with all this is the following:
No #0, no #var in the design (#constant is OK)
-> Same as current behaviour, scheduling not adjusted,
same code generated as before
Has static #0 and '--no-sched-zero-delay' is NOT given:
-> No warnings, scheduling adjusted so it just works, runs slow
Has static #0 and '--no-sched-zero-delay' is given:
-> ZERODLY on the #0, scheduling not adjusted, fails at runtime if hit
No static #0, but has #var and no option is given:
-> ZERODLY on the #var advising use of '--no-sched-zero-delay' or
'--sched-zero-delay' (similar to '--timing'), scheduling adjusted
assuming it can be a zero delay and it just works
No static #0, but has #var and '--no-sched-zero-delay' is given:
-> No warning, scheduling not adjusted, fails at runtime if zero delay
No static #0, but has #var and '--sched-zero-delay' is given:
-> No warning, scheduling adjusted so it just works
2026-02-16 04:55:55 +01:00
|
|
|
SCHED_RESUME_ZERO_DELAY,
|
2025-09-27 14:22:17 +02:00
|
|
|
SCHED_RESUMPTION,
|
|
|
|
|
SCHED_TRIGGER,
|
|
|
|
|
UNPACKED_ASSIGN,
|
|
|
|
|
UNPACKED_FILL,
|
|
|
|
|
UNPACKED_NEQ,
|
|
|
|
|
_ENUM_MAX // Leave last
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct Item final {
|
|
|
|
|
enum en m_e; // Method's enum mnemonic, for checking
|
|
|
|
|
const char* m_name; // Method name, printed into C++
|
|
|
|
|
bool m_pure; // Method being called is pure
|
|
|
|
|
};
|
|
|
|
|
static Item s_itemData[];
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VCMethod()
|
|
|
|
|
: m_e{_NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCMethod(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VCMethod(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const VL_PURE { return s_itemData[m_e].m_name; }
|
|
|
|
|
bool isPure() const VL_PURE { return s_itemData[m_e].m_pure; }
|
|
|
|
|
// Return array method for given name
|
|
|
|
|
static VCMethod arrayMethod(const string& name);
|
|
|
|
|
static void selfTest();
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCMethod& lhs, const VCMethod& rhs) { return lhs.m_e == rhs.m_e; }
|
|
|
|
|
constexpr bool operator==(const VCMethod& lhs, VCMethod::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VCMethod::en lhs, const VCMethod& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Entries in this table need to match above VCMethod enum table
|
|
|
|
|
//
|
|
|
|
|
// {Mnemonic, C++ method, pure}
|
|
|
|
|
#define V3AST_VCMETHOD_ITEMDATA_DECL \
|
|
|
|
|
VCMethod::Item VCMethod::s_itemData[] \
|
|
|
|
|
= {{_NONE, "_none", false}, \
|
|
|
|
|
{ARRAY_AND, "and", true}, \
|
|
|
|
|
{ARRAY_AT, "at", true}, \
|
|
|
|
|
{ARRAY_AT_BACK, "atBack", true}, \
|
|
|
|
|
{ARRAY_AT_WRITE, "atWrite", true}, \
|
|
|
|
|
{ARRAY_FIND, "find", true}, \
|
|
|
|
|
{ARRAY_FIND_FIRST, "find_first", true}, \
|
|
|
|
|
{ARRAY_FIND_FIRST_INDEX, "find_first_index", true}, \
|
|
|
|
|
{ARRAY_FIND_INDEX, "find_index", true}, \
|
|
|
|
|
{ARRAY_FIND_LAST, "find_last", true}, \
|
|
|
|
|
{ARRAY_FIND_LAST_INDEX, "find_last_index", true}, \
|
|
|
|
|
{ARRAY_FIRST, "first", false}, \
|
|
|
|
|
{ARRAY_INSIDE, "inside", true}, \
|
|
|
|
|
{ARRAY_LAST, "last", false}, \
|
2026-03-24 10:38:50 +01:00
|
|
|
{ARRAY_MAP, "map", true}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{ARRAY_MAX, "max", true}, \
|
|
|
|
|
{ARRAY_MIN, "min", true}, \
|
|
|
|
|
{ARRAY_NEXT, "next", false}, \
|
|
|
|
|
{ARRAY_OR, "or", true}, \
|
|
|
|
|
{ARRAY_POP_BACK, "pop_back", false}, \
|
|
|
|
|
{ARRAY_POP_FRONT, "pop_front", false}, \
|
|
|
|
|
{ARRAY_PREV, "prev", false}, \
|
|
|
|
|
{ARRAY_PRODUCT, "product", true}, \
|
|
|
|
|
{ARRAY_PUSH_BACK, "push_back", false}, \
|
|
|
|
|
{ARRAY_PUSH_FRONT, "push_front", false}, \
|
|
|
|
|
{ARRAY_REVERSE, "reverse", false}, \
|
|
|
|
|
{ARRAY_RSORT, "rsort", false}, \
|
|
|
|
|
{ARRAY_R_AND, "r_and", true}, \
|
|
|
|
|
{ARRAY_R_OR, "r_or", true}, \
|
|
|
|
|
{ARRAY_R_PRODUCT, "r_product", true}, \
|
|
|
|
|
{ARRAY_R_SUM, "r_sum", true}, \
|
|
|
|
|
{ARRAY_R_XOR, "r_xor", true}, \
|
|
|
|
|
{ARRAY_SHUFFLE, "shuffle", false}, \
|
|
|
|
|
{ARRAY_SORT, "sort", false}, \
|
|
|
|
|
{ARRAY_SUM, "sum", true}, \
|
|
|
|
|
{ARRAY_UNIQUE, "unique", true}, \
|
|
|
|
|
{ARRAY_UNIQUE_INDEX, "unique_index", true}, \
|
|
|
|
|
{ARRAY_XOR, "xor", true}, \
|
|
|
|
|
{ASSOC_CLEAR, "clear", false}, \
|
|
|
|
|
{ASSOC_ERASE, "erase", false}, \
|
|
|
|
|
{ASSOC_EXISTS, "exists", true}, \
|
|
|
|
|
{ASSOC_FIRST, "first", false}, \
|
|
|
|
|
{ASSOC_NEXT, "next", false}, \
|
|
|
|
|
{ASSOC_SIZE, "size", true}, \
|
|
|
|
|
{CLASS_SET_RANDMODE, "set_randmode", false}, \
|
|
|
|
|
{DYN_AT_WRITE_APPEND, "atWriteAppend", false}, \
|
|
|
|
|
{DYN_AT_WRITE_APPEND_BACK, "atWriteAppendBack", false}, \
|
|
|
|
|
{DYN_CLEAR, "clear", false}, \
|
|
|
|
|
{DYN_ERASE, "erase", false}, \
|
|
|
|
|
{DYN_INSERT, "insert", false}, \
|
|
|
|
|
{DYN_POP, "pop", false}, \
|
|
|
|
|
{DYN_POP_FRONT, "pop_front", false}, \
|
|
|
|
|
{DYN_PUSH, "push", false}, \
|
|
|
|
|
{DYN_PUSH_FRONT, "push_front", false}, \
|
|
|
|
|
{DYN_RENEW, "renew", false}, \
|
|
|
|
|
{DYN_RENEW_COPY, "renew_copy", false}, \
|
|
|
|
|
{DYN_RESIZE, "resize", false}, \
|
|
|
|
|
{DYN_SIZE, "size", true}, \
|
|
|
|
|
{DYN_SLICE, "slice", true}, \
|
2026-03-17 20:10:49 +01:00
|
|
|
{DYN_SLICE_ASSIGN, "sliceAssign", false}, \
|
|
|
|
|
{DYN_SLICE_ASSIGN_BACK_BACK, "sliceAssignBackBack", false}, \
|
|
|
|
|
{DYN_SLICE_ASSIGN_FRONT_BACK, "sliceAssignFrontBack", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{DYN_SLICE_BACK_BACK, "sliceBackBack", true}, \
|
|
|
|
|
{DYN_SLICE_FRONT_BACK, "sliceFrontBack", true}, \
|
|
|
|
|
{EVENT_CLEAR_FIRED, "clearFired", false}, \
|
|
|
|
|
{EVENT_CLEAR_TRIGGERED, "clearTriggered", false}, \
|
|
|
|
|
{EVENT_FIRE, "fire", false}, \
|
|
|
|
|
{EVENT_IS_FIRED, "isFired", true}, \
|
|
|
|
|
{EVENT_IS_TRIGGERED, "isTriggered", true}, \
|
2026-04-21 17:54:42 +02:00
|
|
|
{FORCE_ADD, "addForce", false}, \
|
|
|
|
|
{FORCE_READ, "read", true}, \
|
|
|
|
|
{FORCE_READ_INDEX, "readIndex", true}, \
|
2026-05-14 13:38:42 +02:00
|
|
|
{FORCE_READ_SEL, "readSel", true}, \
|
2026-04-21 17:54:42 +02:00
|
|
|
{FORCE_RELEASE, "release", false}, \
|
|
|
|
|
{FORCE_TOUCH, "touch", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{FORK_DONE, "done", false}, \
|
|
|
|
|
{FORK_INIT, "init", false}, \
|
|
|
|
|
{FORK_JOIN, "join", false}, \
|
2026-03-24 03:56:31 +01:00
|
|
|
{FORK_ON_KILL, "onKill", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{RANDOMIZER_BASIC_STD_RANDOMIZATION, "basicStdRandomization", false}, \
|
2025-11-14 20:32:01 +01:00
|
|
|
{RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false}, \
|
|
|
|
|
{RANDOMIZER_CLEARALL, "clearAll", false}, \
|
2026-03-03 17:23:14 +01:00
|
|
|
{RANDOMIZER_DISABLE_SOFT, "disable_soft", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{RANDOMIZER_HARD, "hard", false}, \
|
2026-03-01 21:16:55 +01:00
|
|
|
{RANDOMIZER_SOFT, "soft", false}, \
|
2026-01-16 14:42:09 +01:00
|
|
|
{RANDOMIZER_UNIQUE, "rand_unique", false}, \
|
2026-02-12 16:58:04 +01:00
|
|
|
{RANDOMIZER_MARK_RANDC, "markRandc", false}, \
|
2026-02-22 17:33:18 +01:00
|
|
|
{RANDOMIZER_SOLVE_BEFORE, "solveBefore", false}, \
|
2026-03-11 11:51:32 +01:00
|
|
|
{RANDOMIZER_PIN_VAR, "pin_var", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{RANDOMIZER_WRITE_VAR, "write_var", false}, \
|
2026-03-17 20:09:14 +01:00
|
|
|
{RANDOMIZER_SET_VAR_DISABLED, "set_var_disabled", false}, \
|
|
|
|
|
{RANDOMIZER_CLEAR_VAR_DISABLED, "clear_var_disabled", false}, \
|
2026-04-29 23:07:27 +02:00
|
|
|
{RANDOMIZER_MARK_VAR_STATIC, "mark_var_static", false}, \
|
|
|
|
|
{RANDOMIZER_SET_STATIC_RANDMODE, "set_static_randmode", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{RNG_GET_RANDSTATE, "__Vm_rng.get_randstate", true}, \
|
|
|
|
|
{RNG_SET_RANDSTATE, "__Vm_rng.set_randstate", false}, \
|
|
|
|
|
{SCHED_ANY_TRIGGERED, "anyTriggered", false}, \
|
|
|
|
|
{SCHED_AWAITING_CURRENT_TIME, "awaitingCurrentTime", true}, \
|
Support #0 delays with IEEE-1800 compliant semantics (#7079)
This patch adds IEEE-1800 compliant scheduling support for the Inactive
scheduling region used for #0 delays.
Implementing this requires that **all** IEEE-1800 active region events
are placed in the internal 'act' section. This has simulation
performance implications. It prevents some optimizations (e.g.
V3LifePost), which reduces single threaded performance. It also reduces
the available work and parallelism in the internal 'nba' section, which
reduced the effectiveness of multi-threading severely.
Performance impact on RTLMeter when using scheduling adjusted to support
proper #0 delays is ~10-20% slowdown in single-threaded mode, and ~100%
(2x slower) with --threads 4.
To avoid paying this performance penalty unconditionally, the scheduling
is only adjusted if either:
1. The input contains a statically known #0 delay
2. The input contains a variable #x delay unknown at compile time
If no #0 is present, but #x variable delays are, a ZERODLY warning is
issued advising the use of '--no-sched-zero-delay' which is a promise
by the user that none of the variable delays will evaluate to a zero
delay at run-time. This warning is turned off if '--sched-zero-delay'
is explicitly given. This is similar to the '--timing' option.
If '--no-sched-zero-delay' was used at compile time, then executing
a zero delay will fail at runtime.
A ZERODLY warning is also issued if a static #0 if found, but the user
specified '--no-sched-zero-delay'. In this case the scheduling is not
adjusted to support #0, so executing it will fail at runtime. Presumably
the user knows it won't be executed.
The intended behaviour with all this is the following:
No #0, no #var in the design (#constant is OK)
-> Same as current behaviour, scheduling not adjusted,
same code generated as before
Has static #0 and '--no-sched-zero-delay' is NOT given:
-> No warnings, scheduling adjusted so it just works, runs slow
Has static #0 and '--no-sched-zero-delay' is given:
-> ZERODLY on the #0, scheduling not adjusted, fails at runtime if hit
No static #0, but has #var and no option is given:
-> ZERODLY on the #var advising use of '--no-sched-zero-delay' or
'--sched-zero-delay' (similar to '--timing'), scheduling adjusted
assuming it can be a zero delay and it just works
No static #0, but has #var and '--no-sched-zero-delay' is given:
-> No warning, scheduling not adjusted, fails at runtime if zero delay
No static #0, but has #var and '--sched-zero-delay' is given:
-> No warning, scheduling adjusted so it just works
2026-02-16 04:55:55 +01:00
|
|
|
{SCHED_AWAITING_ZERO_DELAY, "awaitingZeroDelay", true}, \
|
2026-02-11 19:35:59 +01:00
|
|
|
{SCHED_READY, "ready", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{SCHED_COMMIT, "commit", false}, \
|
2026-02-11 19:35:59 +01:00
|
|
|
{SCHED_MOVE_TO_RESUME_QUEUE, "moveToResumeQueue", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{SCHED_DELAY, "delay", false}, \
|
|
|
|
|
{SCHED_DO_POST_UPDATES, "doPostUpdates", false}, \
|
|
|
|
|
{SCHED_ENQUEUE, "enqueue", false}, \
|
|
|
|
|
{SCHED_EVALUATE, "evaluate", false}, \
|
|
|
|
|
{SCHED_EVALUATION, "evaluation", false}, \
|
|
|
|
|
{SCHED_POST_UPDATE, "postUpdate", false}, \
|
|
|
|
|
{SCHED_RESUME, "resume", false}, \
|
Support #0 delays with IEEE-1800 compliant semantics (#7079)
This patch adds IEEE-1800 compliant scheduling support for the Inactive
scheduling region used for #0 delays.
Implementing this requires that **all** IEEE-1800 active region events
are placed in the internal 'act' section. This has simulation
performance implications. It prevents some optimizations (e.g.
V3LifePost), which reduces single threaded performance. It also reduces
the available work and parallelism in the internal 'nba' section, which
reduced the effectiveness of multi-threading severely.
Performance impact on RTLMeter when using scheduling adjusted to support
proper #0 delays is ~10-20% slowdown in single-threaded mode, and ~100%
(2x slower) with --threads 4.
To avoid paying this performance penalty unconditionally, the scheduling
is only adjusted if either:
1. The input contains a statically known #0 delay
2. The input contains a variable #x delay unknown at compile time
If no #0 is present, but #x variable delays are, a ZERODLY warning is
issued advising the use of '--no-sched-zero-delay' which is a promise
by the user that none of the variable delays will evaluate to a zero
delay at run-time. This warning is turned off if '--sched-zero-delay'
is explicitly given. This is similar to the '--timing' option.
If '--no-sched-zero-delay' was used at compile time, then executing
a zero delay will fail at runtime.
A ZERODLY warning is also issued if a static #0 if found, but the user
specified '--no-sched-zero-delay'. In this case the scheduling is not
adjusted to support #0, so executing it will fail at runtime. Presumably
the user knows it won't be executed.
The intended behaviour with all this is the following:
No #0, no #var in the design (#constant is OK)
-> Same as current behaviour, scheduling not adjusted,
same code generated as before
Has static #0 and '--no-sched-zero-delay' is NOT given:
-> No warnings, scheduling adjusted so it just works, runs slow
Has static #0 and '--no-sched-zero-delay' is given:
-> ZERODLY on the #0, scheduling not adjusted, fails at runtime if hit
No static #0, but has #var and no option is given:
-> ZERODLY on the #var advising use of '--no-sched-zero-delay' or
'--sched-zero-delay' (similar to '--timing'), scheduling adjusted
assuming it can be a zero delay and it just works
No static #0, but has #var and '--no-sched-zero-delay' is given:
-> No warning, scheduling not adjusted, fails at runtime if zero delay
No static #0, but has #var and '--sched-zero-delay' is given:
-> No warning, scheduling adjusted so it just works
2026-02-16 04:55:55 +01:00
|
|
|
{SCHED_RESUME_ZERO_DELAY, "resumeZeroDelay", false}, \
|
2025-09-27 14:22:17 +02:00
|
|
|
{SCHED_RESUMPTION, "resumption", false}, \
|
|
|
|
|
{SCHED_TRIGGER, "trigger", false}, \
|
|
|
|
|
{UNPACKED_ASSIGN, "assign", false}, \
|
|
|
|
|
{UNPACKED_FILL, "fill", false}, \
|
|
|
|
|
{UNPACKED_NEQ, "neq", true}, \
|
|
|
|
|
{_ENUM_MAX, "_ENUM_MAX", false}};
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
2025-09-27 14:19:57 +02:00
|
|
|
|
2026-03-23 23:10:34 +01:00
|
|
|
class VCStmtType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
NONE, // Unknown or not applicable
|
|
|
|
|
CTOR_VAR_RESET_CALL,
|
|
|
|
|
_ENUM_MAX // Leave last
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct Item final {
|
|
|
|
|
enum en m_e; // Statement's enum mnemonic, for checking
|
|
|
|
|
const char* m_name; // Statements name, for debugging
|
|
|
|
|
};
|
|
|
|
|
static Item s_itemData[];
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VCStmtType()
|
|
|
|
|
: m_e{NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCStmtType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VCStmtType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const VL_PURE {
|
|
|
|
|
static const char* const names[] = {"none", "ctor_var_reset_call"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool isNone() const { return m_e == NONE; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCStmtType& lhs, const VCStmtType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VCStmtType& lhs, VCStmtType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VCStmtType::en lhs, const VCStmtType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VCStmtType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
2025-09-27 14:19:57 +02:00
|
|
|
class VCaseType final {
|
|
|
|
|
public:
|
2026-01-17 20:15:52 +01:00
|
|
|
enum en : uint8_t {
|
|
|
|
|
CT_CASE,
|
|
|
|
|
CT_CASEX,
|
|
|
|
|
CT_CASEZ,
|
|
|
|
|
CT_CASEINSIDE,
|
|
|
|
|
CT_CASEMATCHES,
|
|
|
|
|
CT_RANDSEQUENCE
|
|
|
|
|
};
|
2025-09-27 14:19:57 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
VCaseType()
|
|
|
|
|
: m_e{CT_CASE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCaseType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VCaseType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCaseType& lhs, const VCaseType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VCastable final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
UNSUPPORTED,
|
|
|
|
|
SAMEISH,
|
|
|
|
|
COMPATIBLE,
|
|
|
|
|
ENUM_EXPLICIT,
|
|
|
|
|
ENUM_IMPLICIT,
|
|
|
|
|
DYNAMIC_CLASS,
|
|
|
|
|
INCOMPATIBLE,
|
|
|
|
|
_ENUM_MAX // Leave last
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"UNSUPPORTED", "SAMEISH", "COMPATIBLE", "ENUM_EXPLICIT",
|
|
|
|
|
"ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool isAssignable() const { return m_e != UNSUPPORTED && m_e != INCOMPATIBLE; }
|
|
|
|
|
VCastable()
|
|
|
|
|
: m_e{UNSUPPORTED} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCastable(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VCastable(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCastable& lhs, const VCastable& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VCastable& lhs, VCastable::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VCastable::en lhs, const VCastable& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2026-06-05 15:35:01 +02:00
|
|
|
|
|
|
|
|
class VCoverBinsType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
BINS_ARRAY, // Array of bins with user-speciifed size
|
|
|
|
|
BINS_AUTO, // Auto-sized array of bins (eg auto_bin_max)
|
|
|
|
|
BINS_DEFAULT, // Default bin
|
|
|
|
|
BINS_IGNORE, // Ignore bin
|
|
|
|
|
BINS_ILLEGAL, // Illegal bin
|
|
|
|
|
BINS_TRANSITION, // Transition bin
|
|
|
|
|
BINS_USER, // Single bin with one or more values/ranges
|
|
|
|
|
BINS_WILDCARD // Wildcard bin
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VCoverBinsType() // LCOV_EXCL_START
|
|
|
|
|
: m_e{BINS_USER} {} // LCOV_EXCL_STOP
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCoverBinsType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
constexpr operator en() const { return m_e; } // LCOV_EXCL_LINE
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2026-06-12 17:40:48 +02:00
|
|
|
// VlCovBinKind enumerator naming the bin's set
|
|
|
|
|
const char* binSetEnum() const {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case BINS_IGNORE: return "VlCovBinKind::KIND_IGNORE";
|
|
|
|
|
case BINS_ILLEGAL: return "VlCovBinKind::KIND_ILLEGAL";
|
|
|
|
|
case BINS_DEFAULT: return "VlCovBinKind::KIND_DEFAULT";
|
|
|
|
|
default: return "VlCovBinKind::KIND_NORMAL";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Normal bins (feed coverage) are anything but ignore/illegal/default
|
|
|
|
|
bool binIsNormal() const {
|
|
|
|
|
return m_e != BINS_IGNORE && m_e != BINS_ILLEGAL && m_e != BINS_DEFAULT;
|
|
|
|
|
}
|
2026-06-05 15:35:01 +02:00
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCoverBinsType& lhs, VCoverBinsType::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VCoverOptionType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
// Shared by option.* and type_option.*
|
|
|
|
|
WEIGHT,
|
|
|
|
|
GOAL,
|
|
|
|
|
AT_LEAST,
|
|
|
|
|
AUTO_BIN_MAX,
|
|
|
|
|
PER_INSTANCE,
|
|
|
|
|
COMMENT,
|
|
|
|
|
// option.* only (IEEE 1800-2023 Table 19-1)
|
|
|
|
|
NAME,
|
|
|
|
|
CROSS_NUM_PRINT_MISSING,
|
|
|
|
|
CROSS_RETAIN_AUTO_BINS,
|
|
|
|
|
DETECT_OVERLAP,
|
|
|
|
|
GET_INST_COVERAGE,
|
|
|
|
|
// type_option.* only (IEEE 1800-2023 Table 19-3)
|
|
|
|
|
STROBE,
|
|
|
|
|
MERGE_INSTANCES,
|
|
|
|
|
DISTRIBUTE_FIRST,
|
|
|
|
|
REAL_INTERVAL,
|
|
|
|
|
// sentinel - should never appear after parse-time validation
|
|
|
|
|
UNKNOWN
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VCoverOptionType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"weight",
|
|
|
|
|
"goal",
|
|
|
|
|
"at_least",
|
|
|
|
|
"auto_bin_max",
|
|
|
|
|
"per_instance",
|
|
|
|
|
"comment",
|
|
|
|
|
"name",
|
|
|
|
|
"cross_num_print_missing",
|
|
|
|
|
"cross_retain_auto_bins",
|
|
|
|
|
"detect_overlap",
|
|
|
|
|
"get_inst_coverage",
|
|
|
|
|
"strobe",
|
|
|
|
|
"merge_instances",
|
|
|
|
|
"distribute_first",
|
|
|
|
|
"real_interval",
|
|
|
|
|
"unknown"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VCoverOptionType& lhs, VCoverOptionType::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VTransRepType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
NONE, // No repetition
|
|
|
|
|
CONSEC, // Consecutive repetition [*]
|
|
|
|
|
GOTO, // Goto repetition [->]
|
|
|
|
|
NONCONS // Nonconsecutive repetition [=]
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VTransRepType() // LCOV_EXCL_START
|
|
|
|
|
: m_e{NONE} {} // LCOV_EXCL_STOP
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VTransRepType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VTransRepType(int _e) // LCOV_EXCL_START
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // LCOV_EXCL_STOP // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; } // LCOV_EXCL_LINE
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"", "[*]", "[->]", "[=]"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* asciiJson() const {
|
|
|
|
|
static const char* const names[] = {"\"none\"", "\"consec\"", "\"goto\"", "\"noncons\""};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2025-09-27 14:19:57 +02:00
|
|
|
|
|
|
|
|
class VDirection final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VDirection()
|
|
|
|
|
: m_e{NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VDirection(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VDirection(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
string verilogKwd() const {
|
|
|
|
|
static const char* const names[] = {"", "input", "output", "inout", "ref", "const ref"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
string prettyName() const { return verilogKwd(); }
|
|
|
|
|
bool isAny() const { return m_e != NONE; }
|
|
|
|
|
bool isInout() const { return m_e == INOUT; }
|
|
|
|
|
bool isInoutOrRef() const { return m_e == INOUT || m_e == REF || m_e == CONSTREF; }
|
|
|
|
|
bool isInput() const { return m_e == INPUT; }
|
|
|
|
|
bool isNonOutput() const {
|
|
|
|
|
return m_e == INPUT || m_e == INOUT || m_e == REF || m_e == CONSTREF;
|
|
|
|
|
}
|
|
|
|
|
bool isReadOnly() const VL_MT_SAFE { return m_e == INPUT || m_e == CONSTREF; }
|
|
|
|
|
bool isWritable() const VL_MT_SAFE { return m_e == OUTPUT || m_e == INOUT || m_e == REF; }
|
|
|
|
|
bool isRef() const VL_MT_SAFE { return m_e == REF; }
|
|
|
|
|
bool isConstRef() const VL_MT_SAFE { return m_e == CONSTREF; }
|
2026-04-15 01:16:21 +02:00
|
|
|
string traceSigDirection() const {
|
|
|
|
|
if (isInout()) {
|
|
|
|
|
return "VerilatedTraceSigDirection::INOUT";
|
|
|
|
|
} else if (isWritable()) {
|
|
|
|
|
return "VerilatedTraceSigDirection::OUTPUT";
|
|
|
|
|
} else if (isNonOutput()) {
|
|
|
|
|
return "VerilatedTraceSigDirection::INPUT";
|
|
|
|
|
}
|
|
|
|
|
return "VerilatedTraceSigDirection::NONE";
|
|
|
|
|
}
|
2025-09-27 14:19:57 +02:00
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VDirection& lhs, VDirection::en rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VDirection::en lhs, const VDirection& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VDisplayType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
DT_DISPLAY,
|
|
|
|
|
DT_WRITE,
|
|
|
|
|
DT_MONITOR,
|
|
|
|
|
DT_STROBE,
|
|
|
|
|
DT_INFO,
|
|
|
|
|
DT_ERROR,
|
|
|
|
|
DT_WARNING,
|
|
|
|
|
DT_FATAL
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VDisplayType()
|
|
|
|
|
: m_e{DT_DISPLAY} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VDisplayType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VDisplayType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
bool addNewline() const { return m_e != DT_WRITE; }
|
|
|
|
|
bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VDisplayType& lhs, const VDisplayType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VDisplayType& lhs, VDisplayType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VDisplayType::en lhs, const VDisplayType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VDumpCtlType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VDumpCtlType()
|
|
|
|
|
: m_e{ON} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VDumpCtlType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VDumpCtlType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush",
|
|
|
|
|
"$dumplimit", "$dumpoff", "$dumpon"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VEdgeType final {
|
|
|
|
|
public:
|
|
|
|
|
// REMEMBER to edit the strings below too
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
// These must be in general -> most specific order, as we sort by it
|
|
|
|
|
// in V3Const::visit AstSenTree
|
|
|
|
|
// Involving a variable
|
|
|
|
|
ET_CHANGED, // Value changed
|
|
|
|
|
ET_BOTHEDGE, // POSEDGE | NEGEDGE (i.e.: 'edge' in Verilog)
|
|
|
|
|
ET_POSEDGE,
|
|
|
|
|
ET_NEGEDGE,
|
|
|
|
|
ET_EVENT, // VlEventBase::isFired
|
|
|
|
|
// Involving an expression
|
|
|
|
|
ET_TRUE,
|
2026-06-20 23:23:05 +02:00
|
|
|
ET_INITIAL_NBA, // Event that is fired initially and never again
|
2025-09-27 14:19:57 +02:00
|
|
|
//
|
|
|
|
|
ET_COMBO, // Sensitive to all combo inputs to this block
|
|
|
|
|
ET_COMBO_STAR, // Sensitive to all combo inputs to this block (from .*)
|
|
|
|
|
ET_HYBRID, // This is like ET_COMB, but with explicit sensitivity to an expression
|
|
|
|
|
ET_STATIC, // static variable initializers (runs before 'initial')
|
|
|
|
|
ET_INITIAL, // 'initial' statements
|
|
|
|
|
ET_FINAL, // 'final' statements
|
|
|
|
|
ET_NEVER // Never occurs (optimized away)
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
bool clockedStmt() const {
|
|
|
|
|
static const bool clocked[] = {
|
|
|
|
|
true, // ET_CHANGED
|
|
|
|
|
true, // ET_BOTHEDGE
|
|
|
|
|
true, // ET_POSEDGE
|
|
|
|
|
true, // ET_NEGEDGE
|
|
|
|
|
true, // ET_EVENT
|
|
|
|
|
true, // ET_TRUE
|
2026-06-20 23:23:05 +02:00
|
|
|
true, // ET_INITIAL_NBA
|
2025-09-27 14:19:57 +02:00
|
|
|
|
|
|
|
|
false, // ET_COMBO
|
|
|
|
|
false, // ET_COMBO_STAR
|
|
|
|
|
false, // ET_HYBRID
|
|
|
|
|
false, // ET_STATIC
|
|
|
|
|
false, // ET_INITIAL
|
|
|
|
|
false, // ET_FINAL
|
|
|
|
|
false, // ET_NEVER
|
|
|
|
|
};
|
|
|
|
|
return clocked[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool anEdge() const { return m_e == ET_BOTHEDGE || m_e == ET_POSEDGE || m_e == ET_NEGEDGE; }
|
|
|
|
|
VEdgeType invert() const {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case ET_CHANGED: return ET_CHANGED;
|
|
|
|
|
case ET_BOTHEDGE: return ET_BOTHEDGE;
|
|
|
|
|
case ET_POSEDGE: return ET_NEGEDGE;
|
|
|
|
|
case ET_NEGEDGE: return ET_POSEDGE;
|
|
|
|
|
default: UASSERT_STATIC(0, "Inverting bad edgeType()"); return ET_NEGEDGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
2026-06-20 23:23:05 +02:00
|
|
|
= {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "ET_INITIAL_NBA",
|
|
|
|
|
"COMBO", "COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
2025-09-27 14:19:57 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* verilogKwd() const {
|
2026-06-20 23:23:05 +02:00
|
|
|
static const char* const names[] = {
|
|
|
|
|
"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "[initial_nba]",
|
|
|
|
|
"*", "*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
2025-09-27 14:19:57 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
// Return true iff this and the other have mutually exclusive transitions
|
|
|
|
|
bool exclusiveEdge(const VEdgeType& other) const {
|
|
|
|
|
switch (m_e) {
|
|
|
|
|
case VEdgeType::ET_POSEDGE:
|
|
|
|
|
if (other.m_e == VEdgeType::ET_NEGEDGE) return true;
|
|
|
|
|
break;
|
|
|
|
|
case VEdgeType::ET_NEGEDGE:
|
|
|
|
|
if (other.m_e == VEdgeType::ET_POSEDGE) return true;
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VEdgeType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VEdgeType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VFwdType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { NONE, ENUM, STRUCT, UNION, CLASS, INTERFACE_CLASS, GENERIC_INTERFACE };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"none", "enum", "struct", "union", "class", "interface class", "generic interface"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
VFwdType()
|
|
|
|
|
: m_e{NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VFwdType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VFwdType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
// Is a node type compatible with the declaration
|
|
|
|
|
bool isNodeCompatible(const AstNode* nodep) const;
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VFwdType& lhs, const VFwdType& rhs) { return lhs.m_e == rhs.m_e; }
|
|
|
|
|
constexpr bool operator==(const VFwdType& lhs, VFwdType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VFwdType::en lhs, const VFwdType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VFwdType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VIsCached final {
|
|
|
|
|
// Used in some nodes to cache results of boolean methods
|
|
|
|
|
// If cachedCnt == 0, not cached
|
|
|
|
|
// else if cachedCnt == s_cachedCntGbl, then m_state is if cached
|
|
|
|
|
uint64_t m_cachedCnt : 63; // Mark of when cache was computed
|
|
|
|
|
uint64_t m_state : 1;
|
|
|
|
|
static uint64_t s_cachedCntGbl; // Global computed count
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
VIsCached()
|
|
|
|
|
: m_cachedCnt{0}
|
|
|
|
|
, m_state{0} {}
|
|
|
|
|
bool isCached() const { return m_cachedCnt == s_cachedCntGbl; }
|
|
|
|
|
bool get() const { return m_state; }
|
|
|
|
|
void set(bool flag) {
|
|
|
|
|
m_cachedCnt = s_cachedCntGbl;
|
|
|
|
|
m_state = flag;
|
|
|
|
|
}
|
|
|
|
|
void clearCache() {
|
|
|
|
|
m_cachedCnt = 0;
|
|
|
|
|
m_state = 0;
|
|
|
|
|
}
|
|
|
|
|
static void clearCacheTree() {
|
|
|
|
|
++s_cachedCntGbl;
|
|
|
|
|
// 64 bits so won't overflow
|
|
|
|
|
// UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
/// Join type
|
|
|
|
|
class VJoinType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
|
|
|
|
VJoinType()
|
|
|
|
|
: m_e{JOIN} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VJoinType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VJoinType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2025-10-24 15:00:07 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2025-09-27 14:19:57 +02:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* verilogKwd() const {
|
|
|
|
|
static const char* const names[] = {"join", "join_any", "join_none"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool join() const { return m_e == JOIN; }
|
|
|
|
|
bool joinAny() const { return m_e == JOIN_ANY; }
|
|
|
|
|
bool joinNone() const { return m_e == JOIN_NONE; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VJoinType& lhs, const VJoinType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VLifetime final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
NONE,
|
|
|
|
|
AUTOMATIC_EXPLICIT, // Automatic assigned by user
|
|
|
|
|
AUTOMATIC_IMPLICIT, // AUtomatic propagated from above
|
|
|
|
|
STATIC_EXPLICIT, // Static assigned by user
|
|
|
|
|
STATIC_IMPLICIT
|
|
|
|
|
}; // Static propagated from above
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"NONE", "VAUTOM", "VAUTOMI", "VSTATIC", "VSTATICI"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
VLifetime()
|
|
|
|
|
: m_e{NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VLifetime(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VLifetime(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
bool isNone() const { return m_e == NONE; }
|
|
|
|
|
bool isAutomatic() const { return m_e == AUTOMATIC_EXPLICIT || m_e == AUTOMATIC_IMPLICIT; }
|
|
|
|
|
bool isStatic() const { return m_e == STATIC_EXPLICIT || m_e == STATIC_IMPLICIT; }
|
|
|
|
|
bool isStaticExplicit() const { return m_e == STATIC_EXPLICIT; }
|
2026-03-28 04:14:18 +01:00
|
|
|
VLifetime makeImplicit() const {
|
2025-09-27 14:19:57 +02:00
|
|
|
switch (m_e) {
|
|
|
|
|
case AUTOMATIC_EXPLICIT: return AUTOMATIC_IMPLICIT;
|
|
|
|
|
case STATIC_EXPLICIT: return STATIC_IMPLICIT;
|
|
|
|
|
default: return m_e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VLifetime& lhs, const VLifetime& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
// VNumRange - Structure containing numeric range information
|
|
|
|
|
// See also AstRange, which is a symbolic version of this
|
|
|
|
|
|
|
|
|
|
class VNumRange final {
|
|
|
|
|
public:
|
|
|
|
|
int m_left = 0;
|
|
|
|
|
int m_right = 0;
|
|
|
|
|
bool m_ranged = false; // Has a range
|
|
|
|
|
bool operator==(const VNumRange& rhs) const {
|
|
|
|
|
return m_left == rhs.m_left && m_right == rhs.m_right && m_ranged == rhs.m_ranged;
|
|
|
|
|
}
|
|
|
|
|
bool operator<(const VNumRange& rhs) const {
|
|
|
|
|
if ((m_left < rhs.m_left)) return true;
|
|
|
|
|
if (!(m_left == rhs.m_left)) return false; // lhs > rhs
|
|
|
|
|
if ((m_right < rhs.m_right)) return true;
|
|
|
|
|
if (!(m_right == rhs.m_right)) return false; // lhs > rhs
|
|
|
|
|
if ((m_ranged < rhs.m_ranged)) return true;
|
|
|
|
|
if (!(m_ranged == rhs.m_ranged)) return false; // lhs > rhs
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
VNumRange() = default;
|
|
|
|
|
VNumRange(int hi, int lo, bool ascending) { init(hi, lo, ascending); }
|
|
|
|
|
VNumRange(int left, int right)
|
|
|
|
|
: m_left{left}
|
|
|
|
|
, m_right{right}
|
|
|
|
|
, m_ranged{true} {}
|
|
|
|
|
~VNumRange() = default;
|
|
|
|
|
// MEMBERS
|
|
|
|
|
void init(int hi, int lo, bool ascending) {
|
2026-03-30 02:33:06 +02:00
|
|
|
if (lo > hi) std::swap(hi, lo);
|
2025-09-27 14:19:57 +02:00
|
|
|
m_left = ascending ? lo : hi;
|
|
|
|
|
m_right = ascending ? hi : lo;
|
|
|
|
|
m_ranged = true;
|
|
|
|
|
}
|
|
|
|
|
int left() const { return m_left; }
|
|
|
|
|
int right() const { return m_right; }
|
|
|
|
|
int hi() const VL_MT_SAFE {
|
|
|
|
|
return m_left > m_right ? m_left : m_right;
|
|
|
|
|
} // How to show a declaration
|
|
|
|
|
int lo() const VL_MT_SAFE {
|
|
|
|
|
return m_left > m_right ? m_right : m_left;
|
|
|
|
|
} // How to show a declaration
|
|
|
|
|
int leftToRightInc() const { return ascending() ? 1 : -1; }
|
|
|
|
|
int elements() const VL_MT_SAFE { return hi() - lo() + 1; }
|
|
|
|
|
bool ranged() const { return m_ranged; }
|
|
|
|
|
bool ascending() const { return m_left < m_right; }
|
|
|
|
|
int hiMaxSelect() const {
|
|
|
|
|
return (lo() < 0 ? hi() - lo() : hi());
|
|
|
|
|
} // Maximum value a [] select may index
|
|
|
|
|
void dump(std::ostream& str) const {
|
|
|
|
|
if (ranged()) {
|
|
|
|
|
str << "[" << left() << ":" << right() << "]";
|
|
|
|
|
} else {
|
|
|
|
|
str << "[norg]";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
|
|
|
|
|
rhs.dump(os);
|
|
|
|
|
return os;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VPragmaType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
COVERAGE_BLOCK_OFF,
|
|
|
|
|
HIER_BLOCK,
|
|
|
|
|
HIER_PARAMS,
|
|
|
|
|
INLINE_MODULE,
|
|
|
|
|
NO_INLINE_MODULE,
|
|
|
|
|
NO_INLINE_TASK,
|
|
|
|
|
PUBLIC_MODULE,
|
|
|
|
|
PUBLIC_TASK,
|
|
|
|
|
TIMEUNIT_SET,
|
|
|
|
|
UNROLL_DISABLE,
|
|
|
|
|
UNROLL_FULL,
|
|
|
|
|
FULL_CASE,
|
|
|
|
|
PARALLEL_CASE,
|
2026-02-13 02:54:03 +01:00
|
|
|
VERILATOR_LIB,
|
2025-10-22 17:04:15 +02:00
|
|
|
_ENUM_SIZE
|
2025-09-27 14:19:57 +02:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
2025-10-22 17:04:15 +02:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {
|
|
|
|
|
"COVERAGE_BLOCK_OFF", //
|
|
|
|
|
"HIER_BLOCK", //
|
|
|
|
|
"HIER_PARAMS", //
|
|
|
|
|
"INLINE_MODULE", //
|
|
|
|
|
"NO_INLINE_MODULE", //
|
|
|
|
|
"NO_INLINE_TASK", //
|
|
|
|
|
"PUBLIC_MODULE", //
|
|
|
|
|
"PUBLIC_TASK", //
|
|
|
|
|
"TIMEUNIT_SET", //
|
|
|
|
|
"UNROLL_DISABLE", //
|
|
|
|
|
"UNROLL_FULL", //
|
|
|
|
|
"FULL_CASE", //
|
|
|
|
|
"PARALLEL_CASE", //
|
2026-02-13 02:54:03 +01:00
|
|
|
"VERILATOR_LIB", //
|
2025-10-22 17:04:15 +02:00
|
|
|
"_ENUM_SIZE" //
|
|
|
|
|
};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2025-09-27 14:19:57 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VPragmaType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VPragmaType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VPragmaType& lhs, const VPragmaType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VPragmaType& lhs, VPragmaType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VPragmaType::en lhs, const VPragmaType& rhs) { return lhs == rhs.m_e; }
|
2025-10-22 17:04:15 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VPragmaType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2025-09-27 14:19:57 +02:00
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
// Defines what kind of randomization is done on a variable
|
|
|
|
|
|
|
|
|
|
class VRandAttr final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
NONE, // Not randomizable
|
|
|
|
|
RAND, // Has a rand modifier
|
|
|
|
|
RAND_CYCLIC, // Has a randc modifier
|
|
|
|
|
RAND_INLINE // Not rand/randc, but used in inline random variable control
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"NONE", "RAND", "RANDC", "RAND_INLINE"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
VRandAttr()
|
|
|
|
|
: m_e{NONE} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VRandAttr(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
bool isRandomizable() const { return m_e != NONE; }
|
|
|
|
|
bool isRand() const { return m_e == RAND || m_e == RAND_CYCLIC; }
|
|
|
|
|
bool isRandC() const { return m_e == RAND_CYCLIC; }
|
|
|
|
|
};
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VRandAttr& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
// VSelfPointerText - Represents text to be emitted before a given var reference, call, etc. to
|
|
|
|
|
// serve as a pointer to a 'self' object. For example, it could be empty (no self pointer), or the
|
|
|
|
|
// string 'this', or 'vlSymsp->...'
|
|
|
|
|
|
|
|
|
|
class VSelfPointerText final {
|
|
|
|
|
// STATIC MEMBERS
|
|
|
|
|
// Keep these in shared pointers to avoid branching for special cases
|
|
|
|
|
static const std::shared_ptr<const string> s_emptyp; // Holds ""
|
|
|
|
|
static const std::shared_ptr<const string> s_thisp; // Holds "this"
|
|
|
|
|
|
|
|
|
|
// MEMBERS
|
|
|
|
|
std::shared_ptr<const string> m_strp;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
class Empty {}; // for creator type-overload selection
|
|
|
|
|
explicit VSelfPointerText(Empty)
|
|
|
|
|
: m_strp{s_emptyp} {}
|
|
|
|
|
class This {}; // for creator type-overload selection
|
|
|
|
|
explicit VSelfPointerText(This)
|
|
|
|
|
: m_strp{s_thisp} {}
|
|
|
|
|
VSelfPointerText(This, const string& field)
|
|
|
|
|
: m_strp{std::make_shared<const string>("this->" + field)} {}
|
|
|
|
|
class VlSyms {}; // for creator type-overload selection
|
|
|
|
|
VSelfPointerText(VlSyms, const string& field)
|
|
|
|
|
: m_strp{std::make_shared<const string>("(&vlSymsp->" + field + ')')} {}
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
bool isEmpty() const { return m_strp == s_emptyp; }
|
|
|
|
|
bool isVlSym() const { return m_strp->find("vlSymsp") != string::npos; }
|
|
|
|
|
bool hasThis() const { return m_strp == s_thisp || VString::startsWith(*m_strp, "this"); }
|
|
|
|
|
string protect(bool useSelfForThis, bool protect) const;
|
|
|
|
|
static string replaceThis(bool useSelfForThis, const string& text);
|
|
|
|
|
const std::string& asString() const { return *m_strp; }
|
|
|
|
|
bool operator==(const VSelfPointerText& other) const { return *m_strp == *other.m_strp; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VSigning final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
UNSIGNED,
|
|
|
|
|
SIGNED,
|
|
|
|
|
NOSIGN,
|
|
|
|
|
_ENUM_MAX // Leave last
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
VSigning()
|
|
|
|
|
: m_e{UNSIGNED} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VSigning(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
static VSigning fromBool(bool isSigned) { // Factory method
|
|
|
|
|
return isSigned ? VSigning{SIGNED} : VSigning{UNSIGNED};
|
|
|
|
|
}
|
|
|
|
|
explicit VSigning(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
bool isSigned() const VL_MT_SAFE { return m_e == SIGNED; }
|
|
|
|
|
bool isNosign() const VL_MT_SAFE { return m_e == NOSIGN; }
|
|
|
|
|
// No isUnsigned() as it's ambiguous if NOSIGN should be included or not.
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VSigning& lhs, const VSigning& rhs) { return lhs.m_e == rhs.m_e; }
|
|
|
|
|
constexpr bool operator==(const VSigning& lhs, VSigning::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VSigning::en lhs, const VSigning& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VStrength final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VStrength(en strengthLevel)
|
|
|
|
|
: m_e{strengthLevel} {}
|
|
|
|
|
explicit VStrength(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VStrength& lhs, const VStrength& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VStrength& lhs, VStrength::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VStrength::en lhs, const VStrength& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-14 12:23:23 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// VSystemCSectionType - Represents the type of a `systemc_* block (Verilator specific extension)
|
|
|
|
|
|
|
|
|
|
class VSystemCSectionType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
CTOR, // `systemc_ctor
|
|
|
|
|
DTOR, // `systemc_dtor
|
|
|
|
|
HDR, // `systemc_header
|
|
|
|
|
HDR_POST, // `systemc_header_post
|
|
|
|
|
IMP, // `systemc_implementation
|
|
|
|
|
IMP_HDR, // `systemc_imp_header
|
|
|
|
|
INT // `systemc_interface
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"`systemc_ctor", //
|
|
|
|
|
"`systemc_dtor", //
|
|
|
|
|
"`systemc_header", //
|
|
|
|
|
"`systemc_header_post", //
|
|
|
|
|
"`systemc_implementation", //
|
|
|
|
|
"`systemc_imp_header", //
|
|
|
|
|
"`systemc_interface"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VSystemCSectionType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-27 14:19:57 +02:00
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VTracePrefixType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
// Note: Entries must match VerilatedTracePrefixType
|
|
|
|
|
ARRAY_PACKED,
|
|
|
|
|
ARRAY_UNPACKED,
|
|
|
|
|
SCOPE_MODULE,
|
|
|
|
|
SCOPE_INTERFACE,
|
|
|
|
|
STRUCT_PACKED,
|
|
|
|
|
STRUCT_UNPACKED,
|
|
|
|
|
UNION_PACKED,
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VTracePrefixType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"ARRAY_PACKED", "ARRAY_UNPACKED", "SCOPE_MODULE", "SCOPE_INTERFACE",
|
|
|
|
|
"STRUCT_PACKED", "STRUCT_UNPACKED", "UNION_PACKED"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VTracePrefixType& lhs, const VTracePrefixType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VTracePrefixType& lhs, VTracePrefixType::en rhs) {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VTracePrefixType::en lhs, const VTracePrefixType& rhs) {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VTracePrefixType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VTraceType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
CONSTANT, // Constant value dump (once at the beginning)
|
|
|
|
|
FULL, // Full value dump (always emitted)
|
|
|
|
|
CHANGE // Incremental value dump (emitted only if the value changed)
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VTraceType()
|
|
|
|
|
: m_e{CONSTANT} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VTraceType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VTraceType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"CONSTANT", "FULL", "CHANGE"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2026-04-15 01:16:21 +02:00
|
|
|
const char* func_prefix() const {
|
|
|
|
|
static const char* const names[] = {"trace_const", "trace_full", "trace_chg"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2025-09-27 14:19:57 +02:00
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VTraceType& lhs, const VTraceType& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VTraceType& lhs, VTraceType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VTraceType::en lhs, const VTraceType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VTraceType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class VUseType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
// Enum values are compared with <, so order matters
|
|
|
|
|
INT_FWD_CLASS = 1 << 0, // Interface (.h) needs a forward class declaration
|
|
|
|
|
INT_INCLUDE = 1 << 1, // Interface (.h) needs an include
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VUseType()
|
|
|
|
|
: m_e{INT_FWD_CLASS} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VUseType(en _e)
|
|
|
|
|
: m_e{_e} {}
|
|
|
|
|
explicit VUseType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
2026-03-28 04:14:18 +01:00
|
|
|
bool containsAny(VUseType other) const { return m_e & other.m_e; }
|
2025-09-27 14:19:57 +02:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"INT_FWD", "INT_INC", "INT_FWD_INC"};
|
|
|
|
|
return names[m_e - 1];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; }
|
|
|
|
|
constexpr bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; }
|
|
|
|
|
constexpr VUseType::en operator|(VUseType::en lhs, VUseType::en rhs) {
|
2026-03-28 04:14:18 +01:00
|
|
|
return VUseType::en(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
|
|
|
|
constexpr VUseType::en operator&(VUseType::en lhs, VUseType::en rhs) {
|
2026-03-28 04:14:18 +01:00
|
|
|
return VUseType::en(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
|
2025-09-27 14:19:57 +02:00
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
class VVarType final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t {
|
|
|
|
|
UNKNOWN,
|
|
|
|
|
GPARAM,
|
|
|
|
|
LPARAM,
|
|
|
|
|
SPECPARAM,
|
|
|
|
|
GENVAR,
|
|
|
|
|
VAR, // Reg, integer, logic, etc
|
|
|
|
|
SUPPLY0,
|
|
|
|
|
SUPPLY1,
|
|
|
|
|
WIRE,
|
|
|
|
|
WREAL,
|
|
|
|
|
TRIAND,
|
|
|
|
|
TRIOR,
|
|
|
|
|
TRIWIRE,
|
|
|
|
|
TRI0,
|
|
|
|
|
TRI1,
|
|
|
|
|
PORT, // Used in parser to recognize ports
|
|
|
|
|
BLOCKTEMP,
|
|
|
|
|
MODULETEMP,
|
|
|
|
|
STMTTEMP,
|
|
|
|
|
XTEMP,
|
|
|
|
|
IFACEREF, // Used to link Interfaces between modules
|
|
|
|
|
MEMBER
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
VVarType() VL_MT_SAFE : m_e{UNKNOWN} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
|
|
|
|
constexpr VVarType(en _e) VL_MT_SAFE : m_e{_e} {}
|
|
|
|
|
explicit VVarType(int _e)
|
|
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
|
|
|
|
constexpr operator en() const { return m_e; }
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"?", "GPARAM", "LPARAM", "SPECPARAM", "GENVAR", "VAR",
|
|
|
|
|
"SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "TRIAND", "TRIOR",
|
|
|
|
|
"TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP", "MODULETEMP",
|
|
|
|
|
"STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool isParam() const { return m_e == GPARAM || m_e == LPARAM; }
|
|
|
|
|
bool isSignal() const {
|
|
|
|
|
return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
|
|
|
|
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR || m_e == TRIOR
|
|
|
|
|
|| m_e == TRIAND);
|
|
|
|
|
}
|
|
|
|
|
bool isNet() const {
|
|
|
|
|
return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0
|
|
|
|
|
|| m_e == SUPPLY1 || m_e == TRIOR || m_e == TRIAND);
|
|
|
|
|
}
|
|
|
|
|
bool isWor() const { return (m_e == TRIOR); }
|
|
|
|
|
bool isWiredNet() const { return (m_e == TRIOR || m_e == TRIAND); }
|
|
|
|
|
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
|
|
|
|
|
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE
|
|
|
|
|
|| m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP
|
|
|
|
|
|| m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF);
|
|
|
|
|
}
|
|
|
|
|
bool isProcAssignable() const {
|
|
|
|
|
return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP
|
|
|
|
|
|| m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF
|
|
|
|
|
|| m_e == MEMBER);
|
|
|
|
|
}
|
|
|
|
|
bool isTemp() const {
|
|
|
|
|
return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
|
|
|
|
|
}
|
|
|
|
|
bool isVPIAccessible() const {
|
|
|
|
|
return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == SPECPARAM || m_e == PORT
|
|
|
|
|
|| m_e == WIRE || m_e == TRI0 || m_e == TRI1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* traceSigKind() const {
|
|
|
|
|
// VerilatedTraceSigKind to used in trace signal declaration
|
|
|
|
|
static const char* const lut[] = {
|
|
|
|
|
/* UNKNOWN: */ "", // Should not be traced
|
|
|
|
|
/* GPARAM: */ "PARAMETER",
|
|
|
|
|
/* LPARAM: */ "PARAMETER",
|
|
|
|
|
/* SPECPARAM: */ "PARAMETER",
|
|
|
|
|
/* GENVAR: */ "PARAMETER",
|
|
|
|
|
/* VAR: */ "VAR",
|
|
|
|
|
/* SUPPLY0: */ "SUPPLY0",
|
|
|
|
|
/* SUPPLY1: */ "SUPPLY1",
|
|
|
|
|
/* WIRE: */ "WIRE",
|
|
|
|
|
/* WREAL: */ "WIRE",
|
|
|
|
|
/* TRIAND: */ "TRIAND",
|
|
|
|
|
/* TRIOR: */ "TRIOR",
|
|
|
|
|
/* TRIWIRE: */ "TRI",
|
|
|
|
|
/* TRI0: */ "TRI0",
|
|
|
|
|
/* TRI1: */ "TRI1",
|
|
|
|
|
/* PORT: */ "WIRE",
|
|
|
|
|
/* BLOCKTEMP: */ "VAR",
|
|
|
|
|
/* MODULETEMP: */ "VAR",
|
|
|
|
|
/* STMTTEMP: */ "VAR",
|
|
|
|
|
/* XTEMP: */ "VAR",
|
|
|
|
|
/* IFACEREF: */ "", // Should not be traced directly
|
|
|
|
|
/* MEMBER: */ "VAR",
|
|
|
|
|
};
|
|
|
|
|
return lut[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VVarType& lhs, VVarType::en rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(VVarType::en lhs, const VVarType& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VVarType& rhs) VL_MT_SAFE {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
|
|
|
|
|
|
// Not in sorted order, as depends on above classes
|
|
|
|
|
class VBasicTypeKey final {
|
|
|
|
|
public:
|
|
|
|
|
const int m_width; // From AstNodeDType: Bit width of operation
|
|
|
|
|
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
|
|
|
|
|
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
|
|
|
|
|
const VSigning m_numeric; // From AstNodeDType: Node is signed
|
|
|
|
|
const VBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
|
|
|
|
|
bool operator==(const VBasicTypeKey& rhs) const {
|
|
|
|
|
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
|
|
|
|
|
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
|
|
|
|
|
}
|
|
|
|
|
bool operator<(const VBasicTypeKey& rhs) const {
|
|
|
|
|
if ((m_width < rhs.m_width)) return true;
|
|
|
|
|
if (!(m_width == rhs.m_width)) return false; // lhs > rhs
|
|
|
|
|
if ((m_widthMin < rhs.m_widthMin)) return true;
|
|
|
|
|
if (!(m_widthMin == rhs.m_widthMin)) return false; // lhs > rhs
|
|
|
|
|
if ((m_numeric < rhs.m_numeric)) return true;
|
|
|
|
|
if (!(m_numeric == rhs.m_numeric)) return false; // lhs > rhs
|
|
|
|
|
if ((m_keyword < rhs.m_keyword)) return true;
|
|
|
|
|
if (!(m_keyword == rhs.m_keyword)) return false; // lhs > rhs
|
|
|
|
|
if ((m_nrange < rhs.m_nrange)) return true;
|
|
|
|
|
if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
VBasicTypeKey(int width, int widthMin, VSigning numeric, VBasicDTypeKwd kwd,
|
|
|
|
|
const VNumRange& nrange)
|
|
|
|
|
: m_width{width}
|
|
|
|
|
, m_widthMin{widthMin}
|
|
|
|
|
, m_nrange{nrange}
|
|
|
|
|
, m_numeric{numeric}
|
|
|
|
|
, m_keyword{kwd} {}
|
|
|
|
|
~VBasicTypeKey() = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|