// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: AstNode attributes and sub-types // // Code available from: https://verilator.org // //************************************************************************* // // This program is free software; you can redistribute it and/or modify it // under the terms of either the GNU Lesser General Public License Version 3 // or the Perl Artistic License Version 2.0. // SPDX-FileCopyrightText: 2003-2026 Wilson Snyder // 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 {}; // ###################################################################### 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; } }; //###################################################################### 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(_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: enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB, CONT_ASSIGN }; 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(_e)) {} // Need () or GCC 4.8 false warning constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"always", "always_ff", "always_latch", "always_comb", "cont_assign"}; 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(_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(_e)) {} // Need () or GCC 4.8 false warning 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); } 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(lhs) | static_cast(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(_e)) {} // Need () or GCC 4.8 false warning bool containsAny(VAssertType other) const { return m_e & other.m_e; } 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); } 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(lhs) | static_cast(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 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 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 VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint 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", "VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC", "VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR" }; // clang-format on return names[m_e]; } VAttrType() : m_e{ILLEGAL} {} // cppcheck-suppress noExplicitConstructor constexpr VAttrType(en _e) : m_e{_e} {} explicit VAttrType(int _e) : m_e(static_cast(_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, // Void type for tagged union members (CVOID to avoid Windows VOID macro) CVOID, 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", "void", "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 { 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"}; 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(_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); } bool isBit() const { return m_e == BIT; } 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 || 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); } bool isCHandle() const VL_MT_SAFE { return m_e == CHANDLE; } 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", /* CVOID: */ "", // Should not be traced /* 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(_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(_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 { if (m_e == BP_UNLIKELY) return BP_LIKELY; if (m_e == BP_LIKELY) return BP_UNLIKELY; return m_e; } 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(); } // ###################################################################### 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, ARRAY_MAP, 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, DYN_SLICE_ASSIGN, DYN_SLICE_ASSIGN_BACK_BACK, DYN_SLICE_ASSIGN_FRONT_BACK, DYN_SLICE_BACK_BACK, DYN_SLICE_FRONT_BACK, EVENT_CLEAR_FIRED, EVENT_CLEAR_TRIGGERED, EVENT_FIRE, EVENT_IS_FIRED, EVENT_IS_TRIGGERED, FORCE_ADD, FORCE_READ, FORCE_READ_INDEX, FORCE_READ_SEL, FORCE_RELEASE, FORCE_TOUCH, FORK_DONE, FORK_INIT, FORK_JOIN, FORK_ON_KILL, RANDOMIZER_BASIC_STD_RANDOMIZATION, RANDOMIZER_CLEARCONSTRAINTS, RANDOMIZER_CLEARALL, RANDOMIZER_DISABLE_SOFT, RANDOMIZER_HARD, RANDOMIZER_SOFT, RANDOMIZER_UNIQUE, RANDOMIZER_MARK_RANDC, RANDOMIZER_SOLVE_BEFORE, RANDOMIZER_PIN_VAR, RANDOMIZER_WRITE_VAR, RANDOMIZER_SET_VAR_DISABLED, RANDOMIZER_CLEAR_VAR_DISABLED, RANDOMIZER_MARK_VAR_STATIC, RANDOMIZER_SET_STATIC_RANDMODE, RNG_GET_RANDSTATE, RNG_SET_RANDSTATE, SCHED_ANY_TRIGGERED, SCHED_AWAITING_CURRENT_TIME, SCHED_AWAITING_ZERO_DELAY, SCHED_READY, SCHED_COMMIT, SCHED_MOVE_TO_RESUME_QUEUE, SCHED_DELAY, SCHED_DO_POST_UPDATES, SCHED_ENQUEUE, SCHED_EVALUATE, SCHED_EVALUATION, SCHED_POST_UPDATE, SCHED_RESUME, SCHED_RESUME_ZERO_DELAY, 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(_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}, \ {ARRAY_MAP, "map", true}, \ {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}, \ {DYN_SLICE_ASSIGN, "sliceAssign", false}, \ {DYN_SLICE_ASSIGN_BACK_BACK, "sliceAssignBackBack", false}, \ {DYN_SLICE_ASSIGN_FRONT_BACK, "sliceAssignFrontBack", false}, \ {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}, \ {FORCE_ADD, "addForce", false}, \ {FORCE_READ, "read", true}, \ {FORCE_READ_INDEX, "readIndex", true}, \ {FORCE_READ_SEL, "readSel", true}, \ {FORCE_RELEASE, "release", false}, \ {FORCE_TOUCH, "touch", false}, \ {FORK_DONE, "done", false}, \ {FORK_INIT, "init", false}, \ {FORK_JOIN, "join", false}, \ {FORK_ON_KILL, "onKill", false}, \ {RANDOMIZER_BASIC_STD_RANDOMIZATION, "basicStdRandomization", false}, \ {RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false}, \ {RANDOMIZER_CLEARALL, "clearAll", false}, \ {RANDOMIZER_DISABLE_SOFT, "disable_soft", false}, \ {RANDOMIZER_HARD, "hard", false}, \ {RANDOMIZER_SOFT, "soft", false}, \ {RANDOMIZER_UNIQUE, "rand_unique", false}, \ {RANDOMIZER_MARK_RANDC, "markRandc", false}, \ {RANDOMIZER_SOLVE_BEFORE, "solveBefore", false}, \ {RANDOMIZER_PIN_VAR, "pin_var", false}, \ {RANDOMIZER_WRITE_VAR, "write_var", false}, \ {RANDOMIZER_SET_VAR_DISABLED, "set_var_disabled", false}, \ {RANDOMIZER_CLEAR_VAR_DISABLED, "clear_var_disabled", false}, \ {RANDOMIZER_MARK_VAR_STATIC, "mark_var_static", false}, \ {RANDOMIZER_SET_STATIC_RANDMODE, "set_static_randmode", false}, \ {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}, \ {SCHED_AWAITING_ZERO_DELAY, "awaitingZeroDelay", true}, \ {SCHED_READY, "ready", false}, \ {SCHED_COMMIT, "commit", false}, \ {SCHED_MOVE_TO_RESUME_QUEUE, "moveToResumeQueue", false}, \ {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}, \ {SCHED_RESUME_ZERO_DELAY, "resumeZeroDelay", false}, \ {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}}; // ###################################################################### 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(_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(); } // ###################################################################### class VCaseType final { public: enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE, CT_CASEMATCHES, CT_RANDSEQUENCE }; 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(_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(_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(); } //###################################################################### 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]; } }; 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(_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]; } }; //###################################################################### 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(_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; } string traceSigDirection() const { if (isInout()) { return "VerilatedTraceSigDirection::INOUT"; } else if (isWritable()) { return "VerilatedTraceSigDirection::OUTPUT"; } else if (isNonOutput()) { return "VerilatedTraceSigDirection::INPUT"; } return "VerilatedTraceSigDirection::NONE"; } }; 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(_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(_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, // 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 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[] = {"CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE", "COMBO", "COMBO_STAR", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"}; return names[m_e]; } const char* verilogKwd() const { static const char* const names[] = {"[changed]", "edge", "posedge", "negedge", "[event]", "[true]", "*", "*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"}; 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(_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(_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(_e)) {} // Need () or GCC 4.8 false warning constexpr operator en() const { return m_e; } 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(_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; } VLifetime makeImplicit() const { 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) { if (lo > hi) std::swap(hi, lo); 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, VERILATOR_LIB, _ENUM_SIZE }; enum en m_e; 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", // "VERILATOR_LIB", // "_ENUM_SIZE" // }; return names[m_e]; } // cppcheck-suppress noExplicitConstructor constexpr VPragmaType(en _e) : m_e{_e} {} explicit VPragmaType(int _e) : m_e(static_cast(_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; } inline std::ostream& operator<<(std::ostream& os, const VPragmaType& rhs) { return os << rhs.ascii(); } // ###################################################################### // 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 s_emptyp; // Holds "" static const std::shared_ptr s_thisp; // Holds "this" // MEMBERS std::shared_ptr 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("this->" + field)} {} class VlSyms {}; // for creator type-overload selection VSelfPointerText(VlSyms, const string& field) : m_strp{std::make_shared("(&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(_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(_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(); } // ###################################################################### // 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; } }; //###################################################################### 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(_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]; } const char* func_prefix() const { static const char* const names[] = {"trace_const", "trace_full", "trace_chg"}; return names[m_e]; } }; 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(_e)) {} // Need () or GCC 4.8 false warning constexpr operator en() const { return m_e; } bool containsAny(VUseType other) const { return m_e & other.m_e; } 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) { return VUseType::en(static_cast(lhs) | static_cast(rhs)); } constexpr VUseType::en operator&(VUseType::en lhs, VUseType::en rhs) { return VUseType::en(static_cast(lhs) & static_cast(rhs)); } 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(_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