1901 lines
73 KiB
C++
1901 lines
73 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: AstNode attributes and sub-types
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you can
|
|
// redistribute it and/or modify it under the terms of either the GNU Lesser
|
|
// General Public License Version 3 or the Perl Artistic License Version 2.0.
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// 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 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:
|
|
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<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[]
|
|
= {"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<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
|
|
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<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; }
|
|
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<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
|
|
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_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<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,
|
|
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",
|
|
"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*", "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<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);
|
|
}
|
|
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 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",
|
|
/* 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 {
|
|
if (m_e == BP_UNLIKELY) {
|
|
return BP_LIKELY;
|
|
} else if (m_e == BP_LIKELY) {
|
|
return BP_UNLIKELY;
|
|
} else {
|
|
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_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_BACK_BACK,
|
|
DYN_SLICE_FRONT_BACK,
|
|
EVENT_CLEAR_FIRED,
|
|
EVENT_CLEAR_TRIGGERED,
|
|
EVENT_FIRE,
|
|
EVENT_IS_FIRED,
|
|
EVENT_IS_TRIGGERED,
|
|
FORK_DONE,
|
|
FORK_INIT,
|
|
FORK_JOIN,
|
|
RANDOMIZER_BASIC_STD_RANDOMIZATION,
|
|
RANDOMIZER_CLEARCONSTRAINTS,
|
|
RANDOMIZER_CLEARALL,
|
|
RANDOMIZER_HARD,
|
|
RANDOMIZER_SOFT,
|
|
RANDOMIZER_WRITE_VAR,
|
|
RNG_GET_RANDSTATE,
|
|
RNG_SET_RANDSTATE,
|
|
SCHED_ANY_TRIGGERED,
|
|
SCHED_AWAITING_CURRENT_TIME,
|
|
SCHED_COMMIT,
|
|
SCHED_DELAY,
|
|
SCHED_DO_POST_UPDATES,
|
|
SCHED_ENQUEUE,
|
|
SCHED_EVALUATE,
|
|
SCHED_EVALUATION,
|
|
SCHED_POST_UPDATE,
|
|
SCHED_RESUME,
|
|
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}, \
|
|
{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_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}, \
|
|
{FORK_DONE, "done", false}, \
|
|
{FORK_INIT, "init", false}, \
|
|
{FORK_JOIN, "join", false}, \
|
|
{RANDOMIZER_BASIC_STD_RANDOMIZATION, "basicStdRandomization", false}, \
|
|
{RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false}, \
|
|
{RANDOMIZER_CLEARALL, "clearAll", false}, \
|
|
{RANDOMIZER_HARD, "hard", false}, \
|
|
{RANDOMIZER_SOFT, "soft", false}, \
|
|
{RANDOMIZER_WRITE_VAR, "write_var", 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_COMMIT, "commit", 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_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 VCaseType final {
|
|
public:
|
|
enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE, 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<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();
|
|
}
|
|
|
|
//######################################################################
|
|
|
|
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 xmlKwd() const { // For historical reasons no "put" suffix
|
|
static const char* const names[] = {"", "in", "out", "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; }
|
|
};
|
|
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,
|
|
//
|
|
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<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
|
|
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<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; }
|
|
VLifetime makeImplicit() {
|
|
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) {
|
|
const int t = hi;
|
|
hi = lo;
|
|
lo = t;
|
|
}
|
|
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,
|
|
_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", //
|
|
"_ENUM_SIZE" //
|
|
};
|
|
return names[m_e];
|
|
}
|
|
// 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; }
|
|
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<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();
|
|
}
|
|
|
|
// ######################################################################
|
|
// 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<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];
|
|
}
|
|
};
|
|
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; }
|
|
bool containsAny(VUseType other) { 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((uint8_t)lhs | (uint8_t)rhs);
|
|
}
|
|
constexpr VUseType::en operator&(VUseType::en lhs, VUseType::en rhs) {
|
|
return VUseType::en((uint8_t)lhs & (uint8_t)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<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
|