2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Ast node structure
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2021-03-04 03:57:07 +01:00
|
|
|
#ifndef VERILATOR_V3AST_H_
|
|
|
|
|
#define VERILATOR_V3AST_H_
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Broken.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Error.h"
|
2014-11-22 17:48:39 +01:00
|
|
|
#include "V3FileLine.h"
|
2022-10-20 14:48:44 +02:00
|
|
|
#include "V3FunctionTraits.h"
|
2011-11-30 04:09:50 +01:00
|
|
|
#include "V3Global.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Number.h"
|
2022-10-20 14:48:44 +02:00
|
|
|
#include "V3StdFuture.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2022-10-04 12:03:41 +02:00
|
|
|
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2011-09-29 03:35:16 +02:00
|
|
|
#include <cmath>
|
2022-01-09 23:34:10 +01:00
|
|
|
#include <functional>
|
2022-01-08 18:01:39 +01:00
|
|
|
#include <map>
|
|
|
|
|
#include <set>
|
2021-06-17 18:27:45 +02:00
|
|
|
#include <type_traits>
|
2020-08-15 16:03:34 +02:00
|
|
|
#include <unordered_set>
|
2022-01-08 18:01:39 +01:00
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-07-23 02:54:28 +02:00
|
|
|
// Forward declarations
|
|
|
|
|
class V3Graph;
|
|
|
|
|
class ExecMTask;
|
|
|
|
|
|
2009-11-05 04:31:53 +01:00
|
|
|
// Hint class so we can choose constructors
|
2012-03-31 17:10:34 +02:00
|
|
|
class VFlagLogicPacked {};
|
|
|
|
|
class VFlagBitPacked {};
|
2012-03-31 17:22:19 +02:00
|
|
|
class VFlagChildDType {}; // Used by parser.y to select constructor that sets childDType
|
2009-11-05 04:31:53 +01:00
|
|
|
|
2018-07-23 02:54:28 +02:00
|
|
|
// Used as key for another map, needs operator<, hence not an unordered_set
|
2021-03-13 00:10:45 +01:00
|
|
|
using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
|
2018-07-23 02:54:28 +02:00
|
|
|
|
2018-07-14 23:27:05 +02:00
|
|
|
//######################################################################
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
// For broken() function, return error string if have a match
|
2020-01-20 22:53:27 +01:00
|
|
|
#define BROKEN_RTN(test) \
|
|
|
|
|
do { \
|
2021-07-11 15:40:41 +02:00
|
|
|
if (VL_UNCOVERABLE(test)) return "'" #test "' @ " __FILE__ ":" VL_STRINGIFY(__LINE__); \
|
2020-04-04 04:31:54 +02:00
|
|
|
} while (false)
|
2020-03-07 18:52:11 +01:00
|
|
|
// For broken() function, return error string if a base of this class has a match
|
|
|
|
|
#define BROKEN_BASE_RTN(test) \
|
|
|
|
|
do { \
|
2021-11-13 19:50:44 +01:00
|
|
|
const char* const reasonp = (test); \
|
2020-03-07 18:52:11 +01:00
|
|
|
if (VL_UNCOVERABLE(reasonp)) return reasonp; \
|
2020-04-04 04:31:54 +02:00
|
|
|
} while (false)
|
2013-05-25 23:05:22 +02:00
|
|
|
|
2021-10-22 16:15:42 +02:00
|
|
|
// (V)erilator (N)ode is: Returns true if and only if AstNode is of the given AstNode subtype,
|
|
|
|
|
// and not nullptr.
|
2021-10-22 18:36:58 +02:00
|
|
|
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(nodep))
|
2018-02-02 03:32:58 +01:00
|
|
|
|
2021-10-22 16:15:42 +02:00
|
|
|
// (V)erilator (N)ode cast: Similar to dynamic_cast, but more efficient, use this instead.
|
|
|
|
|
// Cast to given type if node is of such type, otherwise returns nullptr. If 'nodep' is nullptr,
|
|
|
|
|
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*',
|
|
|
|
|
// a 'const Ast<nodetypename>*' is returned.
|
2021-10-22 18:36:58 +02:00
|
|
|
#define VN_CAST(nodep, nodetypename) \
|
|
|
|
|
(AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
|
2018-02-02 03:32:58 +01:00
|
|
|
|
2021-10-22 16:15:42 +02:00
|
|
|
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Use this to
|
|
|
|
|
// downcast instead of VN_CAST when you know the true type of the node. If 'nodep' is nullptr,
|
|
|
|
|
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*', a 'const
|
|
|
|
|
// Ast<nodetypename>*' is returned.
|
2021-10-22 18:36:58 +02:00
|
|
|
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
|
2021-10-16 20:29:38 +02:00
|
|
|
|
|
|
|
|
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
|
2022-03-27 21:27:40 +02:00
|
|
|
#define VN_DELETED(nodep) VL_UNLIKELY((uint64_t)(nodep) == 0x1)
|
2019-08-04 03:49:39 +02:00
|
|
|
|
2018-02-02 03:32:58 +01:00
|
|
|
//######################################################################
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNType final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2022-10-04 12:03:41 +02:00
|
|
|
#include "V3Ast__gen_type_enum.h" // From ./astgen
|
2006-08-26 13:35:28 +02:00
|
|
|
// Above include has:
|
|
|
|
|
// enum en {...};
|
|
|
|
|
// const char* ascii() const {...};
|
|
|
|
|
enum en m_e;
|
2019-09-09 13:50:21 +02:00
|
|
|
// cppcheck-suppress uninitVar // responsibility of each subclass
|
2022-09-16 14:17:38 +02:00
|
|
|
VNType() = default;
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr VNType(en _e) VL_MT_SAFE : m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VNType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_MT_SAFE {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; }
|
2022-01-02 19:56:40 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VLifetime final {
|
2020-04-26 18:45:06 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { NONE, AUTOMATIC, STATIC };
|
2020-04-26 18:45:06 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"NONE", "VAUTOM", "VSTATIC"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VLifetime()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{NONE} {}
|
2020-04-26 18:45:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VLifetime(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VLifetime(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-04-26 18:45:06 +02:00
|
|
|
bool isNone() const { return m_e == NONE; }
|
|
|
|
|
bool isAutomatic() const { return m_e == AUTOMATIC; }
|
|
|
|
|
bool isStatic() const { return m_e == STATIC; }
|
|
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-07-03 03:02:49 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2020-04-26 18:45:06 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2020-04-26 18:45:06 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VAccess final {
|
2020-09-07 23:09:25 +02:00
|
|
|
public:
|
2020-11-07 16:37:55 +01:00
|
|
|
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
|
|
|
|
|
};
|
2020-09-07 23:09:25 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
2020-11-07 16:37:55 +01:00
|
|
|
static const char* const names[] = {"RD", "WR", "RW", "--"};
|
2020-09-07 23:09:25 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-11-01 22:59:23 +01:00
|
|
|
const char* arrow() const {
|
2020-11-07 16:37:55 +01:00
|
|
|
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
|
2020-11-01 22:59:23 +01:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VAccess()
|
2020-09-07 23:09:25 +02:00
|
|
|
: m_e{READ} {}
|
|
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VAccess(en _e)
|
2020-09-07 23:09:25 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VAccess(int _e)
|
2020-09-07 23:09:25 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-11-07 16:37:55 +01:00
|
|
|
VAccess invert() const {
|
2022-09-16 01:58:01 +02:00
|
|
|
return (m_e == READWRITE) ? VAccess{m_e} : (m_e == WRITE ? VAccess{READ} : VAccess{WRITE});
|
2020-11-07 16:37:55 +01:00
|
|
|
}
|
|
|
|
|
bool isReadOnly() const { return m_e == READ; } // False with READWRITE
|
2021-06-17 19:49:45 +02:00
|
|
|
bool isWriteOnly() const { return m_e == WRITE; } // False with READWRITE
|
2020-11-07 16:37:55 +01:00
|
|
|
bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
|
|
|
|
|
bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
|
2021-01-05 20:26:01 +01:00
|
|
|
bool isRW() const { return m_e == READWRITE; }
|
2020-09-07 23:09:25 +02:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-09-07 23:09:25 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
|
|
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2020-09-07 23:09:25 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VSigning final {
|
2011-07-24 01:58:34 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2019-05-19 22:13:13 +02:00
|
|
|
UNSIGNED,
|
|
|
|
|
SIGNED,
|
|
|
|
|
NOSIGN,
|
|
|
|
|
_ENUM_MAX // Leave last
|
2011-07-24 01:58:34 +02:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"};
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2020-02-04 04:10:29 +01:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VSigning()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{UNSIGNED} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VSigning(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
static VSigning fromBool(bool isSigned) { // Factory method
|
2022-09-16 01:58:01 +02:00
|
|
|
return isSigned ? VSigning{SIGNED} : VSigning{UNSIGNED};
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VSigning(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isSigned() const VL_MT_SAFE { return m_e == SIGNED; }
|
|
|
|
|
bool isNosign() const VL_MT_SAFE { return m_e == NOSIGN; }
|
2012-04-29 16:14:13 +02:00
|
|
|
// No isUnsigned() as it's ambiguous if NOSIGN should be included or not.
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-04-20 03:19:09 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2011-07-24 01:58:34 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2011-07-24 01:58:34 +02:00
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VPragmaType final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2019-05-19 22:13:13 +02:00
|
|
|
ILLEGAL,
|
|
|
|
|
COVERAGE_BLOCK_OFF,
|
2020-08-15 15:43:53 +02:00
|
|
|
HIER_BLOCK,
|
2019-05-19 22:13:13 +02:00
|
|
|
INLINE_MODULE,
|
|
|
|
|
NO_INLINE_MODULE,
|
|
|
|
|
NO_INLINE_TASK,
|
|
|
|
|
PUBLIC_MODULE,
|
2020-01-12 10:03:17 +01:00
|
|
|
PUBLIC_TASK,
|
|
|
|
|
FULL_CASE,
|
|
|
|
|
PARALLEL_CASE,
|
|
|
|
|
ENUM_SIZE
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VPragmaType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{ILLEGAL} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VPragmaType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VPragmaType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VPragmaType& lhs, const VPragmaType& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VEdgeType final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-04-15 13:58:34 +02:00
|
|
|
// REMEMBER to edit the strings below too
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2019-05-19 22:13:13 +02:00
|
|
|
// These must be in general -> most specific order, as we sort by it
|
|
|
|
|
// in V3Const::visit AstSenTree
|
|
|
|
|
ET_ILLEGAL,
|
|
|
|
|
// Involving a variable
|
2022-05-15 17:03:32 +02:00
|
|
|
ET_CHANGED, // Value changed
|
|
|
|
|
ET_BOTHEDGE, // POSEDGE | NEGEDGE (i.e.: 'edge' in Verilog)
|
2019-05-19 22:13:13 +02:00
|
|
|
ET_POSEDGE,
|
|
|
|
|
ET_NEGEDGE,
|
2022-05-15 17:03:32 +02:00
|
|
|
ET_EVENT, // VlEvent::isFired
|
|
|
|
|
// Involving an expression
|
|
|
|
|
ET_TRUE,
|
|
|
|
|
//
|
2020-04-15 13:58:34 +02:00
|
|
|
ET_COMBO, // Sensitive to all combo inputs to this block
|
2022-05-15 17:03:32 +02:00
|
|
|
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
|
2020-04-15 13:58:34 +02:00
|
|
|
ET_NEVER // Never occurs (optimized away)
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
bool clockedStmt() const {
|
2022-05-15 17:03:32 +02:00
|
|
|
static const bool clocked[] = {
|
|
|
|
|
false, // ET_ILLEGAL
|
|
|
|
|
|
|
|
|
|
true, // ET_CHANGED
|
|
|
|
|
true, // ET_BOTHEDGE
|
|
|
|
|
true, // ET_POSEDGE
|
|
|
|
|
true, // ET_NEGEDGE
|
|
|
|
|
true, // ET_EVENT
|
|
|
|
|
true, // ET_TRUE
|
|
|
|
|
|
|
|
|
|
false, // ET_COMBO
|
|
|
|
|
false, // ET_HYBRID
|
|
|
|
|
false, // ET_STATIC
|
|
|
|
|
false, // ET_INITIAL
|
|
|
|
|
false, // ET_FINAL
|
|
|
|
|
false, // ET_NEVER
|
|
|
|
|
};
|
2019-05-19 22:13:13 +02:00
|
|
|
return clocked[m_e];
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-10-15 12:21:34 +02:00
|
|
|
bool anEdge() const { return m_e == ET_BOTHEDGE || m_e == ET_POSEDGE || m_e == ET_NEGEDGE; }
|
2019-10-05 13:54:14 +02:00
|
|
|
VEdgeType invert() const {
|
2019-05-19 22:13:13 +02:00
|
|
|
switch (m_e) {
|
2022-05-15 17:03:32 +02:00
|
|
|
case ET_CHANGED: return ET_CHANGED;
|
2020-04-15 13:58:34 +02:00
|
|
|
case ET_BOTHEDGE: return ET_BOTHEDGE;
|
|
|
|
|
case ET_POSEDGE: return ET_NEGEDGE;
|
|
|
|
|
case ET_NEGEDGE: return ET_POSEDGE;
|
2019-05-19 22:13:13 +02:00
|
|
|
default: UASSERT_STATIC(0, "Inverting bad edgeType()");
|
2020-05-30 19:46:12 +02:00
|
|
|
}
|
2019-10-05 13:54:14 +02:00
|
|
|
return VEdgeType::ET_ILLEGAL;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
const char* ascii() const {
|
2022-06-04 18:30:41 +02:00
|
|
|
static const char* const names[]
|
2022-07-14 13:35:44 +02:00
|
|
|
= {"%E-edge", "CHANGED", "BOTH", "POS", "NEG", "EVENT", "TRUE",
|
|
|
|
|
"COMBO", "HYBRID", "STATIC", "INITIAL", "FINAL", "NEVER"};
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2017-10-28 19:31:04 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
const char* verilogKwd() const {
|
2022-07-14 13:35:44 +02:00
|
|
|
static const char* const names[]
|
|
|
|
|
= {"%E-edge", "[changed]", "edge", "posedge", "negedge", "[event]", "[true]",
|
|
|
|
|
"*", "[hybrid]", "[static]", "[initial]", "[final]", "[never]"};
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2017-10-28 19:31:04 +02:00
|
|
|
}
|
|
|
|
|
// Return true iff this and the other have mutually exclusive transitions
|
2019-10-05 13:54:14 +02:00
|
|
|
bool exclusiveEdge(const VEdgeType& other) const {
|
2017-10-28 19:31:04 +02:00
|
|
|
switch (m_e) {
|
2019-10-05 13:54:14 +02:00
|
|
|
case VEdgeType::ET_POSEDGE:
|
2022-05-15 17:03:32 +02:00
|
|
|
if (other.m_e == VEdgeType::ET_NEGEDGE) return true;
|
2017-10-28 19:31:04 +02:00
|
|
|
break;
|
2019-10-05 13:54:14 +02:00
|
|
|
case VEdgeType::ET_NEGEDGE:
|
2022-05-15 17:03:32 +02:00
|
|
|
if (other.m_e == VEdgeType::ET_POSEDGE) return true;
|
2017-10-28 19:31:04 +02:00
|
|
|
break;
|
2022-05-15 17:03:32 +02:00
|
|
|
default: break;
|
2017-10-28 19:31:04 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VEdgeType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{ET_ILLEGAL} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VEdgeType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VEdgeType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VAttrType final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en: uint8_t {
|
2019-05-19 22:13:13 +02:00
|
|
|
ILLEGAL,
|
|
|
|
|
//
|
|
|
|
|
DIM_BITS, // 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_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
|
|
|
|
ENUM_FIRST, // V3Width processes
|
|
|
|
|
ENUM_LAST, // V3Width processes
|
|
|
|
|
ENUM_NUM, // V3Width processes
|
|
|
|
|
ENUM_NEXT, // V3Width processes
|
|
|
|
|
ENUM_PREV, // V3Width processes
|
|
|
|
|
ENUM_NAME, // V3Width processes
|
2020-12-06 04:58:36 +01:00
|
|
|
ENUM_VALID, // V3Width processes
|
2019-05-19 22:13:13 +02:00
|
|
|
//
|
|
|
|
|
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
|
|
|
|
//
|
2020-01-26 19:21:25 +01:00
|
|
|
TYPENAME, // V3Width processes
|
|
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
2022-05-15 17:03:32 +02:00
|
|
|
VAR_CLOCK_ENABLE, // Ignored, accepted for compatibility
|
2021-12-19 20:45:06 +01:00
|
|
|
VAR_FORCEABLE, // V3LinkParse moves to AstVar::isForceable
|
2019-05-19 22:13:13 +02:00
|
|
|
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_BV, // V3LinkParse moves to AstVar::attrScBv
|
|
|
|
|
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
|
|
|
|
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
2020-02-29 01:15:08 +01:00
|
|
|
VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
|
|
|
|
VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2006-08-26 13:35:28 +02:00
|
|
|
enum en m_e;
|
2009-05-08 00:28:05 +02:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
2019-05-19 22:13:13 +02:00
|
|
|
static const char* const names[] = {
|
|
|
|
|
"%E-AT",
|
|
|
|
|
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
|
|
|
|
|
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
|
|
|
|
|
"DT_PUBLIC",
|
|
|
|
|
"ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
|
2020-12-06 04:58:36 +01:00
|
|
|
"ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
|
2019-05-19 22:13:13 +02:00
|
|
|
"MEMBER_BASE",
|
2020-01-26 19:21:25 +01:00
|
|
|
"TYPENAME",
|
2021-12-19 20:45:06 +01:00
|
|
|
"VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC",
|
2019-05-19 22:13:13 +02:00
|
|
|
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
|
|
|
|
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
2020-02-29 01:15:08 +01:00
|
|
|
"VAR_NO_CLOCKER", "VAR_SPLIT_VAR"
|
2019-05-19 22:13:13 +02:00
|
|
|
};
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2020-02-04 04:10:29 +01:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VAttrType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{ILLEGAL} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VAttrType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VAttrType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VBasicDTypeKwd final {
|
2009-11-02 14:06:04 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2019-05-19 22:13:13 +02:00
|
|
|
UNKNOWN,
|
2020-04-15 13:58:34 +02:00
|
|
|
BIT,
|
|
|
|
|
BYTE,
|
|
|
|
|
CHANDLE,
|
2022-05-15 17:03:32 +02:00
|
|
|
EVENT,
|
2020-04-15 13:58:34 +02:00
|
|
|
INT,
|
|
|
|
|
INTEGER,
|
|
|
|
|
LOGIC,
|
|
|
|
|
LONGINT,
|
|
|
|
|
DOUBLE,
|
|
|
|
|
SHORTINT,
|
|
|
|
|
TIME,
|
2019-05-19 22:13:13 +02:00
|
|
|
// Closer to a class type, but limited usage
|
|
|
|
|
STRING,
|
2022-11-01 23:53:47 +01:00
|
|
|
// Property / Sequence argument type
|
|
|
|
|
UNTYPED,
|
2019-05-19 22:13:13 +02:00
|
|
|
// Internal types for mid-steps
|
2020-04-15 13:58:34 +02:00
|
|
|
SCOPEPTR,
|
|
|
|
|
CHARPTR,
|
2021-06-16 13:18:56 +02:00
|
|
|
MTASKSTATE,
|
2022-05-15 17:03:32 +02:00
|
|
|
TRIGGERVEC,
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
DELAY_SCHEDULER,
|
|
|
|
|
TRIGGER_SCHEDULER,
|
2022-10-22 16:05:39 +02:00
|
|
|
DYNAMIC_TRIGGER_SCHEDULER,
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
FORK_SYNC,
|
2019-05-19 22:13:13 +02:00
|
|
|
// Unsigned and two state; fundamental types
|
2020-04-15 13:58:34 +02:00
|
|
|
UINT32,
|
|
|
|
|
UINT64,
|
2019-05-19 22:13:13 +02:00
|
|
|
// Internal types, eliminated after parsing
|
|
|
|
|
LOGIC_IMPLICIT,
|
|
|
|
|
// Leave last
|
|
|
|
|
_ENUM_MAX
|
2009-11-02 14:06:04 +01:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
|
|
|
|
const char* ascii() const {
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
static const char* const names[] = {"%E-unk",
|
|
|
|
|
"bit",
|
|
|
|
|
"byte",
|
|
|
|
|
"chandle",
|
|
|
|
|
"event",
|
|
|
|
|
"int",
|
|
|
|
|
"integer",
|
|
|
|
|
"logic",
|
|
|
|
|
"longint",
|
|
|
|
|
"real",
|
|
|
|
|
"shortint",
|
|
|
|
|
"time",
|
|
|
|
|
"string",
|
2022-11-01 23:53:47 +01:00
|
|
|
"untyped",
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
"VerilatedScope*",
|
|
|
|
|
"char*",
|
|
|
|
|
"VlMTaskState",
|
|
|
|
|
"VlTriggerVec",
|
|
|
|
|
"VlDelayScheduler",
|
|
|
|
|
"VlTriggerScheduler",
|
2022-10-22 16:05:39 +02:00
|
|
|
"VlDynamicTriggerScheduler",
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
"VlFork",
|
|
|
|
|
"IData",
|
|
|
|
|
"QData",
|
|
|
|
|
"LOGIC_IMPLICIT",
|
|
|
|
|
" MAX"};
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2020-02-04 04:10:29 +01:00
|
|
|
}
|
2009-12-03 12:55:29 +01:00
|
|
|
const char* dpiType() const {
|
2022-10-22 16:05:39 +02:00
|
|
|
static const char* const names[]
|
2022-11-01 23:53:47 +01:00
|
|
|
= {"%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-triggervec", "%E-dly-sched", "%E-trig-sched",
|
|
|
|
|
"%E-dyn-sched", "%E-fork", "IData", "QData", "%E-logic-implct",
|
|
|
|
|
" MAX"};
|
2019-05-19 22:13:13 +02:00
|
|
|
return names[m_e];
|
2020-02-04 04:10:29 +01:00
|
|
|
}
|
2017-10-31 00:01:58 +01:00
|
|
|
static void selfTest() {
|
2022-09-16 01:58:01 +02:00
|
|
|
UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.ascii(), " MAX"),
|
2022-09-15 03:10:19 +02:00
|
|
|
"SelfTest: Enum mismatch");
|
2022-09-16 01:58:01 +02:00
|
|
|
UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.dpiType(), " MAX"),
|
2020-04-15 13:58:34 +02:00
|
|
|
"SelfTest: Enum mismatch");
|
2012-04-14 16:45:24 +02:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
VBasicDTypeKwd()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{UNKNOWN} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VBasicDTypeKwd(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VBasicDTypeKwd(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2009-11-03 04:14:11 +01:00
|
|
|
int width() const {
|
2019-05-19 22:13:13 +02:00
|
|
|
switch (m_e) {
|
2020-04-15 13:58:34 +02:00
|
|
|
case BIT: return 1; // scalar, can't bit extract unless ranged
|
|
|
|
|
case BYTE: return 8;
|
|
|
|
|
case CHANDLE: return 64;
|
2022-05-15 17:03:32 +02:00
|
|
|
case EVENT: return 1;
|
2020-04-15 13:58:34 +02:00
|
|
|
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
|
2021-06-16 13:18:56 +02:00
|
|
|
case MTASKSTATE: return 0; // opaque
|
2022-05-15 17:03:32 +02:00
|
|
|
case TRIGGERVEC: return 0; // opaque
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
case DELAY_SCHEDULER: return 0; // opaque
|
|
|
|
|
case TRIGGER_SCHEDULER: return 0; // opaque
|
2022-10-22 16:05:39 +02:00
|
|
|
case DYNAMIC_TRIGGER_SCHEDULER: return 0; // opaque
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
case FORK_SYNC: return 0; // opaque
|
2020-04-15 13:58:34 +02:00
|
|
|
case UINT32: return 32;
|
|
|
|
|
case UINT64: return 64;
|
2019-05-19 22:13:13 +02:00
|
|
|
default: return 0;
|
|
|
|
|
}
|
2009-11-03 04:14:11 +01:00
|
|
|
}
|
2010-01-15 14:20:25 +01:00
|
|
|
bool isSigned() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER
|
2020-11-29 03:43:37 +01:00
|
|
|
|| m_e == DOUBLE;
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
bool isUnsigned() const {
|
2022-05-15 17:03:32 +02:00
|
|
|
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;
|
2009-11-03 04:14:11 +01:00
|
|
|
}
|
2010-01-15 14:20:25 +01:00
|
|
|
bool isFourstate() const {
|
2020-04-08 01:07:47 +02:00
|
|
|
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
|
2009-11-03 04:14:11 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
bool isZeroInit() const { // Otherwise initializes to X
|
2022-05-15 17:03:32 +02:00
|
|
|
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENT || m_e == INT
|
2020-11-29 03:43:37 +01:00
|
|
|
|| m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE);
|
2009-11-24 01:08:25 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
bool isIntNumeric() const { // Enum increment supported
|
2020-04-15 13:58:34 +02:00
|
|
|
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);
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_e == LOGIC || m_e == BIT);
|
2009-11-03 04:14:11 +01:00
|
|
|
}
|
2012-12-04 02:43:13 +01:00
|
|
|
bool isDpiUnsignable() const { // Can add "unsigned" to DPI
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER);
|
2012-12-04 02:43:13 +01:00
|
|
|
}
|
2017-12-17 22:28:58 +01:00
|
|
|
bool isDpiCLayout() const { // Uses standard C layout, for DPI runtime access
|
2020-04-15 13:58:34 +02:00
|
|
|
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);
|
2017-12-17 22:28:58 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isOpaque() const VL_MT_SAFE { // IE not a simple number we can bit optimize
|
2022-05-15 17:03:32 +02:00
|
|
|
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
|| m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER
|
2022-10-22 16:05:39 +02:00
|
|
|
|| m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC
|
2022-11-01 23:53:47 +01:00
|
|
|
|| m_e == DOUBLE || m_e == UNTYPED);
|
2011-07-06 03:05:35 +02:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
|
2022-05-15 17:03:32 +02:00
|
|
|
bool isEvent() const { return m_e == EVENT; }
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isString() const VL_MT_SAFE { return m_e == STRING; }
|
|
|
|
|
bool isMTaskState() const VL_MT_SAFE { return m_e == MTASKSTATE; }
|
2021-07-22 19:59:03 +02:00
|
|
|
// Does this represent a C++ LiteralType? (can be constexpr)
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isLiteralType() const VL_MT_SAFE {
|
2021-07-22 19:59:03 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr bool operator==(const VBasicDTypeKwd& lhs, VBasicDTypeKwd::en rhs) VL_MT_SAFE {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr bool operator==(VBasicDTypeKwd::en lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
2009-11-02 14:06:04 +01:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VDirection final {
|
2018-10-27 23:29:00 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };
|
2018-10-27 23:29:00 +02:00
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VDirection()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{NONE} {}
|
2018-10-27 23:29:00 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VDirection(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VDirection(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
2018-10-27 23:29:00 +02:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
string verilogKwd() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"", "input", "output", "inout", "ref", "const ref"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
string xmlKwd() const { // For historical reasons no "put" suffix
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"", "in", "out", "inout", "ref", "const ref"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
string prettyName() const { return verilogKwd(); }
|
|
|
|
|
bool isAny() const { return m_e != NONE; }
|
|
|
|
|
// Looks like inout - "ish" because not identical to being an INOUT
|
|
|
|
|
bool isInoutish() const { return m_e == INOUT; }
|
2020-04-15 13:58:34 +02:00
|
|
|
bool isNonOutput() const {
|
|
|
|
|
return m_e == INPUT || m_e == INOUT || m_e == REF || m_e == CONSTREF;
|
|
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
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 isRefOrConstRef() const VL_MT_SAFE { return m_e == REF || m_e == CONSTREF; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) {
|
|
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
constexpr bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2018-10-27 23:29:00 +02:00
|
|
|
|
2019-01-16 06:38:42 +01:00
|
|
|
/// Boolean or unknown
|
2020-11-19 03:32:16 +01:00
|
|
|
class VBoolOrUnknown final {
|
2019-01-16 06:38:42 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END };
|
2019-01-16 06:38:42 +01:00
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
2022-09-16 14:17:38 +02:00
|
|
|
VBoolOrUnknown()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{BU_UNKNOWN} {}
|
2019-01-16 06:38:42 +01:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VBoolOrUnknown(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VBoolOrUnknown(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2019-01-16 06:38:42 +01:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"FALSE", "TRUE", "UNK"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-01 16:57:55 +01:00
|
|
|
bool trueKnown() const { return m_e == BU_TRUE; }
|
|
|
|
|
bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
|
|
|
|
|
bool falseKnown() const { return m_e == BU_FALSE; }
|
|
|
|
|
bool falseUnknown() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
|
2019-01-16 06:38:42 +01:00
|
|
|
bool unknown() const { return m_e == BU_UNKNOWN; }
|
2020-02-01 16:57:55 +01:00
|
|
|
void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2019-01-16 06:38:42 +01:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2020-04-23 03:31:40 +02:00
|
|
|
/// Join type
|
2020-11-19 03:32:16 +01:00
|
|
|
class VJoinType final {
|
2020-04-23 03:31:40 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 };
|
2020-04-23 03:31:40 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
2022-09-16 14:17:38 +02:00
|
|
|
VJoinType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{JOIN} {}
|
2020-04-23 03:31:40 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VJoinType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VJoinType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2020-04-23 03:31:40 +02:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
const char* verilogKwd() const {
|
|
|
|
|
static const char* const names[] = {"join", "join_any", "join_none"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
bool join() const { return m_e == JOIN; }
|
|
|
|
|
bool joinAny() const { return m_e == JOIN_ANY; }
|
|
|
|
|
bool joinNone() const { return m_e == JOIN_NONE; }
|
|
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-04-23 03:31:40 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2020-04-23 03:31:40 +02:00
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VVarType final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2018-10-27 23:29:00 +02:00
|
|
|
UNKNOWN,
|
|
|
|
|
GPARAM,
|
|
|
|
|
LPARAM,
|
|
|
|
|
GENVAR,
|
|
|
|
|
VAR, // Reg, integer, logic, etc
|
|
|
|
|
SUPPLY0,
|
2019-05-19 22:13:13 +02:00
|
|
|
SUPPLY1,
|
|
|
|
|
WIRE,
|
|
|
|
|
WREAL,
|
|
|
|
|
IMPLICITWIRE,
|
|
|
|
|
TRIWIRE,
|
|
|
|
|
TRI0,
|
|
|
|
|
TRI1,
|
2020-04-15 13:58:34 +02:00
|
|
|
PORT, // Temp type used in parser only
|
2019-05-19 22:13:13 +02:00
|
|
|
BLOCKTEMP,
|
|
|
|
|
MODULETEMP,
|
|
|
|
|
STMTTEMP,
|
|
|
|
|
XTEMP,
|
2020-04-11 03:10:21 +02:00
|
|
|
IFACEREF, // Used to link Interfaces between modules
|
2020-11-01 16:56:07 +01:00
|
|
|
MEMBER
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
2022-10-18 23:07:09 +02:00
|
|
|
VVarType() VL_MT_SAFE : m_e{UNKNOWN} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-10-18 23:07:09 +02:00
|
|
|
constexpr VVarType(en _e) VL_MT_SAFE : m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VVarType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2006-08-26 13:35:28 +02:00
|
|
|
const char* ascii() const {
|
2018-10-27 23:29:00 +02:00
|
|
|
static const char* const names[] = {
|
2020-04-15 13:58:34 +02:00
|
|
|
"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
|
|
|
|
"WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT",
|
2020-11-01 16:56:07 +01:00
|
|
|
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
2020-04-15 13:58:34 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2018-11-26 23:58:18 +01:00
|
|
|
bool isSignal() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0
|
|
|
|
|
|| m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
|
2018-11-26 23:58:18 +01:00
|
|
|
}
|
2022-09-14 13:39:27 +02:00
|
|
|
bool isNet() const {
|
|
|
|
|
return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
|
|
|
|
|| m_e == SUPPLY0 || m_e == SUPPLY1);
|
|
|
|
|
}
|
2018-12-01 16:12:10 +01:00
|
|
|
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL
|
|
|
|
|
|| m_e == IMPLICITWIRE || 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);
|
2018-12-01 16:12:10 +01:00
|
|
|
}
|
2018-11-26 23:58:18 +01:00
|
|
|
bool isProcAssignable() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
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
|
2020-11-01 16:56:07 +01:00
|
|
|
|| m_e == MEMBER);
|
2018-11-26 23:58:18 +01:00
|
|
|
}
|
2019-10-27 14:27:18 +01:00
|
|
|
bool isTemp() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
|
2019-10-27 14:27:18 +01:00
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-10-18 23:07:09 +02:00
|
|
|
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 {
|
2020-02-02 16:34:29 +01:00
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VBranchPred final {
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END };
|
2006-08-26 13:35:28 +02:00
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
2022-09-16 14:17:38 +02:00
|
|
|
VBranchPred()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{BP_UNKNOWN} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VBranchPred(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VBranchPred(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2019-10-05 13:54:14 +02:00
|
|
|
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 {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_e == BP_UNLIKELY) {
|
|
|
|
|
return BP_LIKELY;
|
|
|
|
|
} else if (m_e == BP_LIKELY) {
|
|
|
|
|
return BP_UNLIKELY;
|
|
|
|
|
} else {
|
|
|
|
|
return m_e;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"", "VL_LIKELY", "VL_UNLIKELY"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-02-02 16:34:29 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2006-12-21 22:53:51 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VVarAttrClocker final {
|
2015-03-13 00:20:46 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END };
|
2015-03-13 00:20:46 +01:00
|
|
|
enum en m_e;
|
|
|
|
|
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
2022-09-16 14:17:38 +02:00
|
|
|
VVarAttrClocker()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{CLOCKER_UNKNOWN} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VVarAttrClocker(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VVarAttrClocker(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-04-15 13:58:34 +02:00
|
|
|
bool unknown() const { return m_e == CLOCKER_UNKNOWN; }
|
2019-10-05 13:54:14 +02:00
|
|
|
VVarAttrClocker invert() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_e == CLOCKER_YES) {
|
|
|
|
|
return CLOCKER_NO;
|
|
|
|
|
} else if (m_e == CLOCKER_NO) {
|
|
|
|
|
return CLOCKER_YES;
|
|
|
|
|
} else {
|
|
|
|
|
return m_e;
|
|
|
|
|
}
|
2015-03-13 00:20:46 +01:00
|
|
|
}
|
|
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"", "clker", "non_clker"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs == rhs.m_e;
|
|
|
|
|
}
|
|
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2015-03-13 00:20:46 +01:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VAlwaysKwd final {
|
2013-05-01 04:55:28 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB };
|
2013-05-01 04:55:28 +02:00
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VAlwaysKwd()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{ALWAYS} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VAlwaysKwd(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VAlwaysKwd(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2013-05-01 04:55:28 +02:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"always", "always_ff", "always_latch", "always_comb"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2013-05-01 04:55:28 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2013-05-01 04:55:28 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VCaseType final {
|
2008-07-22 19:07:19 +02:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE };
|
2008-07-22 19:07:19 +02:00
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VCaseType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{CT_CASE} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VCaseType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VCaseType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2008-07-22 19:07:19 +02:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2008-07-22 19:07:19 +02:00
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VDisplayType final {
|
2007-03-06 22:43:38 +01:00
|
|
|
public:
|
2020-11-29 17:31:38 +01:00
|
|
|
enum en : uint8_t {
|
|
|
|
|
DT_DISPLAY,
|
|
|
|
|
DT_WRITE,
|
|
|
|
|
DT_MONITOR,
|
|
|
|
|
DT_STROBE,
|
|
|
|
|
DT_INFO,
|
|
|
|
|
DT_ERROR,
|
|
|
|
|
DT_WARNING,
|
|
|
|
|
DT_FATAL
|
|
|
|
|
};
|
2007-03-06 22:43:38 +01:00
|
|
|
enum en m_e;
|
2022-01-02 19:56:40 +01:00
|
|
|
VDisplayType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{DT_DISPLAY} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VDisplayType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VDisplayType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-04-15 13:58:34 +02:00
|
|
|
bool addNewline() const { return m_e != DT_WRITE; }
|
|
|
|
|
bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; }
|
2007-03-06 22:43:38 +01:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[]
|
2020-11-29 17:31:38 +01:00
|
|
|
= {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"};
|
2020-04-15 13:58:34 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VDisplayType& lhs, const VDisplayType& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2007-03-06 22:43:38 +01:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2007-03-06 22:43:38 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VDumpCtlType final {
|
2020-03-02 03:39:23 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
|
2020-03-02 03:39:23 +01:00
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VDumpCtlType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{ON} {}
|
2020-03-02 03:39:23 +01:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VDumpCtlType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VDumpCtlType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-03-02 03:39:23 +01:00
|
|
|
const char* ascii() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush",
|
|
|
|
|
"$dumplimit", "$dumpoff", "$dumpon"};
|
2020-03-02 03:39:23 +01:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) {
|
2020-03-02 03:39:23 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-03-02 03:39:23 +01:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2020-03-02 03:39:23 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VParseRefExp final {
|
2006-12-21 22:53:51 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2020-04-15 13:58:34 +02:00
|
|
|
PX_NONE, // Used in V3LinkParse only
|
2020-05-02 14:29:20 +02:00
|
|
|
PX_ROOT,
|
2020-04-15 13:58:34 +02:00
|
|
|
PX_TEXT // Unknown ID component
|
2006-12-21 22:53:51 +01:00
|
|
|
};
|
|
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VParseRefExp()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{PX_NONE} {}
|
2015-10-04 04:33:06 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VParseRefExp(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VParseRefExp(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2006-12-21 22:53:51 +01:00
|
|
|
const char* ascii() const {
|
2020-05-02 14:29:20 +02:00
|
|
|
static const char* const names[] = {"", "$root", "TEXT", "PREDOT"};
|
2020-04-15 13:58:34 +02:00
|
|
|
return names[m_e];
|
|
|
|
|
}
|
2020-02-02 16:34:29 +01:00
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) {
|
2020-02-02 16:34:29 +01:00
|
|
|
return lhs.m_e == rhs.m_e;
|
|
|
|
|
}
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; }
|
|
|
|
|
constexpr bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; }
|
2020-02-02 16:34:29 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
2006-12-21 22:53:51 +01:00
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2022-09-14 13:39:27 +02:00
|
|
|
|
|
|
|
|
class VStrength final {
|
|
|
|
|
public:
|
|
|
|
|
enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY };
|
|
|
|
|
enum en m_e;
|
|
|
|
|
|
2022-09-15 14:54:04 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VStrength(en strengthLevel)
|
2022-09-14 13:39:27 +02:00
|
|
|
: m_e(strengthLevel) {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VStrength(int _e)
|
2022-09-14 13:39:27 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2022-09-14 13:39:27 +02:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[]
|
|
|
|
|
= {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2022-09-14 13:39:27 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// VNumRange - Structure containing numeric range information
|
|
|
|
|
// See also AstRange, which is a symbolic version of this
|
2012-04-29 16:14:13 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VNumRange final {
|
2019-10-05 13:54:14 +02:00
|
|
|
public:
|
2020-12-07 03:13:56 +01:00
|
|
|
int m_left = 0;
|
|
|
|
|
int m_right = 0;
|
|
|
|
|
bool m_ranged = false; // Has a range
|
2020-12-02 00:49:03 +01:00
|
|
|
bool operator==(const VNumRange& rhs) const {
|
2020-12-07 03:13:56 +01:00
|
|
|
return m_left == rhs.m_left && m_right == rhs.m_right && m_ranged == rhs.m_ranged;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2020-12-02 00:49:03 +01:00
|
|
|
bool operator<(const VNumRange& rhs) const {
|
2020-12-07 03:13:56 +01:00
|
|
|
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
|
2019-05-19 22:13:13 +02:00
|
|
|
return false;
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
//
|
2022-07-30 17:52:35 +02:00
|
|
|
VNumRange() = default;
|
2020-12-07 03:13:56 +01:00
|
|
|
VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); }
|
|
|
|
|
VNumRange(int left, int right)
|
|
|
|
|
: m_left{left}
|
|
|
|
|
, m_right{right}
|
|
|
|
|
, m_ranged{true} {}
|
2020-11-17 01:56:16 +01:00
|
|
|
~VNumRange() = default;
|
2012-04-29 16:14:13 +02:00
|
|
|
// MEMBERS
|
2013-01-18 02:29:20 +01:00
|
|
|
void init(int hi, int lo, bool littleEndian) {
|
2020-12-07 03:13:56 +01:00
|
|
|
if (lo > hi) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const int t = hi;
|
2020-12-07 03:13:56 +01:00
|
|
|
hi = lo;
|
|
|
|
|
lo = t;
|
|
|
|
|
}
|
|
|
|
|
m_left = littleEndian ? lo : hi;
|
|
|
|
|
m_right = littleEndian ? hi : lo;
|
2020-04-15 13:58:34 +02:00
|
|
|
m_ranged = true;
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
2020-12-07 03:13:56 +01:00
|
|
|
int left() const { return m_left; }
|
|
|
|
|
int right() const { return m_right; }
|
2022-10-18 23:07:09 +02:00
|
|
|
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
|
2020-04-15 13:58:34 +02:00
|
|
|
int leftToRightInc() const { return littleEndian() ? 1 : -1; }
|
2022-10-18 23:07:09 +02:00
|
|
|
int elements() const VL_MT_SAFE { return hi() - lo() + 1; }
|
2012-04-29 16:14:13 +02:00
|
|
|
bool ranged() const { return m_ranged; }
|
2020-12-07 03:13:56 +01:00
|
|
|
bool littleEndian() const { return m_left < m_right; }
|
2020-04-15 13:58:34 +02:00
|
|
|
int hiMaxSelect() const {
|
|
|
|
|
return (lo() < 0 ? hi() - lo() : hi());
|
|
|
|
|
} // Maximum value a [] select may index
|
2019-05-19 22:13:13 +02:00
|
|
|
void dump(std::ostream& str) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (ranged()) {
|
|
|
|
|
str << "[" << left() << ":" << right() << "]";
|
|
|
|
|
} else {
|
|
|
|
|
str << "[norg]";
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
};
|
2020-04-15 13:58:34 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
|
|
|
|
|
rhs.dump(os);
|
|
|
|
|
return os;
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VUseType final {
|
2020-02-01 22:45:11 +01:00
|
|
|
public:
|
2020-08-16 18:05:35 +02:00
|
|
|
enum en : uint8_t {
|
2020-02-01 22:45:11 +01:00
|
|
|
IMP_INCLUDE, // Implementation (.cpp) needs an include
|
|
|
|
|
INT_INCLUDE, // Interface (.h) needs an include
|
|
|
|
|
IMP_FWD_CLASS, // Implementation (.cpp) needs a forward class declaration
|
|
|
|
|
INT_FWD_CLASS, // Interface (.h) needs a forward class declaration
|
|
|
|
|
};
|
|
|
|
|
enum en m_e;
|
2022-09-16 14:17:38 +02:00
|
|
|
VUseType()
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{IMP_FWD_CLASS} {}
|
2020-02-01 22:45:11 +01:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr VUseType(en _e)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_e{_e} {}
|
2022-09-16 14:17:38 +02:00
|
|
|
explicit VUseType(int _e)
|
2020-08-18 14:10:44 +02:00
|
|
|
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
2020-02-01 22:45:11 +01:00
|
|
|
bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; }
|
|
|
|
|
bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; }
|
2022-09-23 11:57:01 +02:00
|
|
|
constexpr operator en() const { return m_e; }
|
2020-02-01 22:45:11 +01:00
|
|
|
const char* ascii() const {
|
|
|
|
|
static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"};
|
|
|
|
|
return names[m_e];
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-09-23 11:57:01 +02:00
|
|
|
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; }
|
2020-02-01 22:45:11 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
|
|
|
|
return os << rhs.ascii();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 11:57:01 +02:00
|
|
|
// ######################################################################
|
2020-02-01 22:45:11 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VBasicTypeKey final {
|
2019-10-05 13:54:14 +02:00
|
|
|
public:
|
2021-11-26 23:55:36 +01:00
|
|
|
const int m_width; // From AstNodeDType: Bit width of operation
|
|
|
|
|
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
|
2022-11-13 15:26:46 +01:00
|
|
|
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
|
2021-11-26 23:55:36 +01:00
|
|
|
const VSigning m_numeric; // From AstNodeDType: Node is signed
|
2022-01-02 19:56:40 +01:00
|
|
|
const VBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
|
2020-12-02 00:49:03 +01:00
|
|
|
bool operator==(const VBasicTypeKey& rhs) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2020-12-02 00:49:03 +01:00
|
|
|
bool operator<(const VBasicTypeKey& rhs) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((m_width < rhs.m_width)) return true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!(m_width == rhs.m_width)) return false; // lhs > rhs
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((m_widthMin < rhs.m_widthMin)) return true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!(m_widthMin == rhs.m_widthMin)) return false; // lhs > rhs
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((m_numeric < rhs.m_numeric)) return true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!(m_numeric == rhs.m_numeric)) return false; // lhs > rhs
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((m_keyword < rhs.m_keyword)) return true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!(m_keyword == rhs.m_keyword)) return false; // lhs > rhs
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((m_nrange < rhs.m_nrange)) return true;
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs
|
2020-04-15 13:58:34 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-02 19:56:40 +01:00
|
|
|
VBasicTypeKey(int width, int widthMin, VSigning numeric, VBasicDTypeKwd kwd,
|
2019-05-19 22:13:13 +02:00
|
|
|
const VNumRange& nrange)
|
2020-08-16 17:40:42 +02:00
|
|
|
: m_width{width}
|
|
|
|
|
, m_widthMin{widthMin}
|
2022-11-13 15:26:46 +01:00
|
|
|
, m_nrange{nrange}
|
2020-08-16 17:40:42 +02:00
|
|
|
, m_numeric{numeric}
|
2022-11-13 15:26:46 +01:00
|
|
|
, m_keyword{kwd} {}
|
2020-11-17 01:56:16 +01:00
|
|
|
~VBasicTypeKey() = default;
|
2012-04-29 16:14:13 +02:00
|
|
|
};
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
2016-11-27 15:40:12 +01:00
|
|
|
// AstNUser - Generic base class for AST User nodes.
|
2019-05-19 22:13:13 +02:00
|
|
|
// - Also used to allow parameter passing up/down iterate calls
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
class WidthVP;
|
|
|
|
|
class V3GraphVertex;
|
2012-06-20 12:13:28 +02:00
|
|
|
class VSymEnt;
|
2016-11-27 15:40:12 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VNUser final {
|
2016-11-27 15:40:12 +01:00
|
|
|
union {
|
2019-05-19 22:13:13 +02:00
|
|
|
void* up;
|
|
|
|
|
int ui;
|
2016-11-27 15:40:12 +01:00
|
|
|
} m_u;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2016-11-27 15:40:12 +01:00
|
|
|
public:
|
2022-07-30 17:52:35 +02:00
|
|
|
VNUser() = default;
|
2017-07-07 02:25:59 +02:00
|
|
|
// non-explicit:
|
2017-10-14 20:51:57 +02:00
|
|
|
// cppcheck-suppress noExplicitConstructor
|
2020-04-15 13:58:34 +02:00
|
|
|
VNUser(int i) {
|
|
|
|
|
m_u.up = 0;
|
|
|
|
|
m_u.ui = i;
|
|
|
|
|
}
|
2017-07-07 02:25:59 +02:00
|
|
|
explicit VNUser(void* p) { m_u.up = p; }
|
2020-11-17 01:56:16 +01:00
|
|
|
~VNUser() = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
// Casters
|
2022-08-05 11:56:57 +02:00
|
|
|
template <class T>
|
2022-10-18 23:07:09 +02:00
|
|
|
typename std::enable_if<std::is_pointer<T>::value, T>::type to() const VL_MT_SAFE {
|
2021-06-17 18:27:45 +02:00
|
|
|
return reinterpret_cast<T>(m_u.up);
|
|
|
|
|
}
|
|
|
|
|
WidthVP* c() const { return to<WidthVP*>(); }
|
|
|
|
|
VSymEnt* toSymEnt() const { return to<VSymEnt*>(); }
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* toNodep() const VL_MT_SAFE { return to<AstNode*>(); }
|
2021-06-17 18:27:45 +02:00
|
|
|
V3GraphVertex* toGraphVertex() const { return to<V3GraphVertex*>(); }
|
2020-06-02 05:16:02 +02:00
|
|
|
int toInt() const { return m_u.ui; }
|
2022-09-16 01:58:01 +02:00
|
|
|
static VNUser fromInt(int i) { return VNUser{i}; }
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
2008-11-21 21:50:33 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// AstUserResource - Generic pointer base class for tracking usage of user()
|
|
|
|
|
//
|
|
|
|
|
// Where AstNode->user2() is going to be used, for example, you write:
|
|
|
|
|
//
|
2022-01-02 19:56:40 +01:00
|
|
|
// VNUser2InUse m_userres;
|
2008-11-21 21:50:33 +01:00
|
|
|
//
|
2019-09-09 13:50:21 +02:00
|
|
|
// This will clear the tree, and prevent another visitor from clobbering
|
2008-11-21 21:50:33 +01:00
|
|
|
// user2. When the member goes out of scope it will be automagically
|
|
|
|
|
// freed up.
|
|
|
|
|
|
2022-01-02 16:32:35 +01:00
|
|
|
class VNUserInUseBase VL_NOT_FINAL {
|
2008-11-21 21:50:33 +01:00
|
|
|
protected:
|
2019-05-19 22:13:13 +02:00
|
|
|
static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
|
|
|
|
|
// Perhaps there's still a AstUserInUse in scope for this?
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser" + cvtToStr(id)
|
|
|
|
|
+ "InUse request when under another AstUserInUse");
|
2019-05-19 22:13:13 +02:00
|
|
|
userBusyRef = true;
|
|
|
|
|
clearcnt(id, cntGblRef, userBusyRef);
|
2008-11-21 21:50:33 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
static void free(int id, uint32_t& cntGblRef, bool& userBusyRef) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_STATIC(userBusyRef, "Free of User" + cvtToStr(id) + "() not under AstUserInUse");
|
2019-05-19 22:13:13 +02:00
|
|
|
clearcnt(id, cntGblRef, userBusyRef); // Includes a checkUse for us
|
|
|
|
|
userBusyRef = false;
|
2008-11-21 21:50:33 +01:00
|
|
|
}
|
2020-02-04 05:21:56 +01:00
|
|
|
static void clearcnt(int id, uint32_t& cntGblRef, const bool& userBusyRef) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_STATIC(userBusyRef, "Clear of User" + cvtToStr(id) + "() not under AstUserInUse");
|
2019-05-19 22:13:13 +02:00
|
|
|
// If this really fires and is real (after 2^32 edits???)
|
|
|
|
|
// we could just walk the tree and clear manually
|
|
|
|
|
++cntGblRef;
|
|
|
|
|
UASSERT_STATIC(cntGblRef, "User*() overflowed!");
|
2008-11-21 21:50:33 +01:00
|
|
|
}
|
2020-02-04 05:21:56 +01:00
|
|
|
static void checkcnt(int id, uint32_t&, const bool& userBusyRef) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UASSERT_STATIC(userBusyRef,
|
|
|
|
|
"Check of User" + cvtToStr(id) + "() failed, not under AstUserInUse");
|
2009-11-08 00:03:23 +01:00
|
|
|
}
|
2008-11-21 21:50:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// For each user() declare the in use structure
|
|
|
|
|
// We let AstNode peek into here, because when under low optimization even
|
|
|
|
|
// an accessor would be way too slow.
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNUser1InUse final : VNUserInUseBase {
|
2008-11-21 21:50:33 +01:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2019-05-19 22:13:13 +02:00
|
|
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
|
|
|
|
static bool s_userBusy; // Count is in use
|
2008-11-21 21:50:33 +01:00
|
|
|
public:
|
2022-01-02 19:56:40 +01:00
|
|
|
VNUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
~VNUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2009-09-24 05:10:46 +02:00
|
|
|
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2009-11-08 00:03:23 +01:00
|
|
|
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2008-11-21 21:50:33 +01:00
|
|
|
};
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNUser2InUse final : VNUserInUseBase {
|
2008-11-21 21:50:33 +01:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2019-05-19 22:13:13 +02:00
|
|
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
|
|
|
|
static bool s_userBusy; // Count is in use
|
2008-11-21 21:50:33 +01:00
|
|
|
public:
|
2022-01-02 19:56:40 +01:00
|
|
|
VNUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
~VNUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2019-05-19 22:13:13 +02:00
|
|
|
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2008-11-21 21:50:33 +01:00
|
|
|
};
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNUser3InUse final : VNUserInUseBase {
|
2008-11-21 21:50:33 +01:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2019-05-19 22:13:13 +02:00
|
|
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
|
|
|
|
static bool s_userBusy; // Count is in use
|
2008-11-21 21:50:33 +01:00
|
|
|
public:
|
2022-01-02 19:56:40 +01:00
|
|
|
VNUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
~VNUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2019-05-19 22:13:13 +02:00
|
|
|
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2008-11-21 21:50:33 +01:00
|
|
|
};
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNUser4InUse final : VNUserInUseBase {
|
2008-11-21 21:50:33 +01:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2019-05-19 22:13:13 +02:00
|
|
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
|
|
|
|
static bool s_userBusy; // Count is in use
|
2008-11-21 21:50:33 +01:00
|
|
|
public:
|
2022-01-02 19:56:40 +01:00
|
|
|
VNUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
~VNUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2019-05-19 22:13:13 +02:00
|
|
|
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2008-11-21 21:50:33 +01:00
|
|
|
};
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNUser5InUse final : VNUserInUseBase {
|
2010-02-02 00:55:32 +01:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2019-05-19 22:13:13 +02:00
|
|
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
|
|
|
|
static bool s_userBusy; // Count is in use
|
2010-02-02 00:55:32 +01:00
|
|
|
public:
|
2022-01-02 19:56:40 +01:00
|
|
|
VNUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
~VNUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2019-05-19 22:13:13 +02:00
|
|
|
static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
|
|
|
|
static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
2010-02-02 00:55:32 +01:00
|
|
|
};
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2008-11-21 21:50:33 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
2021-10-17 12:40:44 +02:00
|
|
|
// Node deleter, deletes all enqueued AstNode* on destruction, or when
|
|
|
|
|
// explicitly told to do so. This is useful when the deletion of removed
|
|
|
|
|
// nodes needs to be deferred to a later time, because pointers to the
|
|
|
|
|
// removed nodes might still exist.
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-01-02 16:32:35 +01:00
|
|
|
class VNDeleter VL_NOT_FINAL {
|
2018-05-14 12:50:47 +02:00
|
|
|
// MEMBERS
|
2021-10-17 12:40:44 +02:00
|
|
|
std::vector<AstNode*> m_deleteps; // Nodes to delete
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2018-05-14 12:50:47 +02:00
|
|
|
// METHODS
|
2021-10-17 12:40:44 +02:00
|
|
|
|
|
|
|
|
// Enqueue node for deletion on next 'doDelete' (or destruction)
|
2020-10-18 19:23:02 +02:00
|
|
|
void pushDeletep(AstNode* nodep) {
|
|
|
|
|
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
|
|
|
|
|
m_deleteps.push_back(nodep);
|
|
|
|
|
}
|
2021-10-17 12:40:44 +02:00
|
|
|
|
|
|
|
|
// Delete all previously pushed nodes (by callint deleteTree)
|
2006-08-26 13:35:28 +02:00
|
|
|
void doDeletes();
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2021-10-17 12:40:44 +02:00
|
|
|
// Do the deletions on destruction
|
2022-01-02 16:32:35 +01:00
|
|
|
virtual ~VNDeleter() { doDeletes(); }
|
2021-10-17 12:40:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2022-01-02 19:56:40 +01:00
|
|
|
// VNVisitor -- Allows new functions to be called on each node
|
2021-10-17 12:40:44 +02:00
|
|
|
// type without changing the base classes. See "Modern C++ Design".
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class VNVisitor VL_NOT_FINAL : public VNDeleter {
|
2021-10-17 12:40:44 +02:00
|
|
|
friend class AstNode;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2018-05-11 02:55:37 +02:00
|
|
|
/// Call visit()s on nodep
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterate(AstNode* nodep);
|
2021-05-21 15:34:27 +02:00
|
|
|
/// Call visit()s on nodep
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateNull(AstNode* nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
/// Call visit()s on nodep's children
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateChildren(AstNode* nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
/// Call visit()s on nodep's children in backp() order
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateChildrenBackwards(AstNode* nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
/// Call visit()s on const nodep's children
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateChildrenConst(AstNode* nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
/// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateAndNextNull(AstNode* nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateAndNextConstNull(AstNode* nodep);
|
2021-12-22 12:41:29 +01:00
|
|
|
/// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
/// Return edited nodep; see comments in V3Ast.cpp
|
2022-09-16 14:17:38 +02:00
|
|
|
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
|
2022-08-02 17:46:31 +02:00
|
|
|
virtual void visit(AstNode* nodep) = 0;
|
|
|
|
|
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2022-01-02 16:32:35 +01:00
|
|
|
// VNRelinker -- Holds the state of a unlink so a new node can be
|
2006-08-26 13:35:28 +02:00
|
|
|
// added at the same point.
|
|
|
|
|
|
2022-01-02 16:32:35 +01:00
|
|
|
class VNRelinker final {
|
2006-08-26 13:35:28 +02:00
|
|
|
protected:
|
|
|
|
|
friend class AstNode;
|
2020-08-16 18:05:35 +02:00
|
|
|
enum RelinkWhatEn : uint8_t {
|
|
|
|
|
RELINK_BAD,
|
|
|
|
|
RELINK_NEXT,
|
|
|
|
|
RELINK_OP1,
|
|
|
|
|
RELINK_OP2,
|
|
|
|
|
RELINK_OP3,
|
|
|
|
|
RELINK_OP4
|
|
|
|
|
};
|
2020-08-15 19:11:27 +02:00
|
|
|
AstNode* m_oldp = nullptr; // The old node that was linked to this point in the tree
|
|
|
|
|
AstNode* m_backp = nullptr;
|
|
|
|
|
AstNode** m_iterpp = nullptr;
|
2022-11-13 15:26:46 +01:00
|
|
|
RelinkWhatEn m_chg = RELINK_BAD;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2022-01-02 16:32:35 +01:00
|
|
|
VNRelinker() = default;
|
2022-09-16 14:17:38 +02:00
|
|
|
inline void relink(AstNode* newp);
|
2006-08-26 13:35:28 +02:00
|
|
|
AstNode* oldp() const { return m_oldp; }
|
2020-04-15 13:58:34 +02:00
|
|
|
void dump(std::ostream& str = std::cout) const;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
2022-01-02 16:32:35 +01:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const VNRelinker& rhs) {
|
2020-04-15 13:58:34 +02:00
|
|
|
rhs.dump(os);
|
|
|
|
|
return os;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// Callback base class to determine if node matches some formula
|
2019-07-14 02:30:32 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VNodeMatcher VL_NOT_FINAL {
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
|
|
|
|
virtual bool nodeMatch(const AstNode* nodep) const { return true; }
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// AstNode -- Base type of all Ast types
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2008-11-22 20:59:22 +01:00
|
|
|
// Prefetch a node.
|
2022-07-31 19:13:55 +02:00
|
|
|
#define ASTNODE_PREFETCH_NON_NULL(nodep) \
|
|
|
|
|
do { \
|
|
|
|
|
VL_PREFETCH_RD(&((nodep)->m_nextp)); \
|
|
|
|
|
VL_PREFETCH_RD(&((nodep)->m_type)); \
|
|
|
|
|
} while (false)
|
2008-11-22 20:59:22 +01:00
|
|
|
// The if() makes it faster, even though prefetch won't fault on null pointers
|
|
|
|
|
#define ASTNODE_PREFETCH(nodep) \
|
2020-05-30 19:46:12 +02:00
|
|
|
do { \
|
2022-07-31 19:13:55 +02:00
|
|
|
if (nodep) ASTNODE_PREFETCH_NON_NULL(nodep); \
|
2020-05-30 19:46:12 +02:00
|
|
|
} while (false)
|
2008-11-22 20:59:22 +01:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class AstNode VL_NOT_FINAL {
|
2008-11-22 20:59:22 +01:00
|
|
|
// v ASTNODE_PREFETCH depends on below ordering of members
|
2022-01-01 17:46:49 +01:00
|
|
|
AstNode* m_nextp = nullptr; // Next peer in the parent's list
|
|
|
|
|
AstNode* m_backp = nullptr; // Node that points to this one (via next/op1/op2/...)
|
|
|
|
|
AstNode* m_op1p = nullptr; // Generic pointer 1
|
|
|
|
|
AstNode* m_op2p = nullptr; // Generic pointer 2
|
|
|
|
|
AstNode* m_op3p = nullptr; // Generic pointer 3
|
|
|
|
|
AstNode* m_op4p = nullptr; // Generic pointer 4
|
|
|
|
|
AstNode** m_iterpp
|
|
|
|
|
= nullptr; // Pointer to node iterating on, change it if we replace this node.
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNType m_type; // Node sub-type identifier
|
2008-11-22 20:59:22 +01:00
|
|
|
// ^ ASTNODE_PREFETCH depends on above ordering of members
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
// VNType is 2 bytes, so we can stick another 6 bytes after it to utilize what would
|
2021-07-10 17:13:05 +02:00
|
|
|
// otherwise be padding (on a 64-bit system). We stick the attribute flags, broken state,
|
|
|
|
|
// and the clone count here.
|
2021-07-10 09:01:58 +02:00
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
bool didWidth : 1; // Did V3Width computation
|
|
|
|
|
bool doingWidth : 1; // Inside V3Width
|
|
|
|
|
bool protect : 1; // Protect name if protection is on
|
2021-07-10 17:13:05 +02:00
|
|
|
// Space for more flags here (there must be 8 bits in total)
|
|
|
|
|
uint8_t unused : 5;
|
2021-07-10 09:01:58 +02:00
|
|
|
} m_flags; // Attribute flags
|
|
|
|
|
|
2021-07-10 17:13:05 +02:00
|
|
|
// State variable used by V3Broken for consistency checking. The top bit of this is byte is a
|
|
|
|
|
// flag, representing V3Broken is currently proceeding under this node. The bottom 7 bits are
|
|
|
|
|
// a generation number. This is hot when --debug-checks so we access as a whole to avoid bit
|
|
|
|
|
// field masking resulting in unnecessary read-modify-write ops.
|
|
|
|
|
uint8_t m_brokenState = 0;
|
|
|
|
|
|
2022-01-01 17:46:49 +01:00
|
|
|
int m_cloneCnt = 0; // Sequence number for when last clone was made
|
2021-07-10 09:01:58 +02:00
|
|
|
|
|
|
|
|
#if defined(__x86_64__) && defined(__gnu_linux__)
|
|
|
|
|
// Only assert this on known platforms, as it only affects performance, not correctness
|
2021-07-10 17:13:05 +02:00
|
|
|
static_assert(sizeof(m_type) + sizeof(m_flags) + sizeof(m_brokenState) + sizeof(m_cloneCnt)
|
|
|
|
|
<= sizeof(void*),
|
2021-07-10 09:01:58 +02:00
|
|
|
"packing requires padding");
|
|
|
|
|
#endif
|
2020-01-25 21:29:44 +01:00
|
|
|
|
2022-01-01 17:46:49 +01:00
|
|
|
AstNodeDType* m_dtypep = nullptr; // Data type of output or assignment (etc)
|
2020-11-16 04:03:06 +01:00
|
|
|
AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list
|
2020-04-15 13:58:34 +02:00
|
|
|
FileLine* m_fileline; // Where it was declared
|
2022-09-24 22:18:43 +02:00
|
|
|
#ifdef VL_DEBUG
|
|
|
|
|
// Only keep track of the edit count in the node in the debug build.
|
|
|
|
|
// In the release build we will take the space saving instead.
|
2022-03-27 21:27:40 +02:00
|
|
|
uint64_t m_editCount; // When it was last edited
|
2022-09-24 22:18:43 +02:00
|
|
|
#endif
|
2022-03-27 21:27:40 +02:00
|
|
|
static uint64_t s_editCntGbl; // Global edit counter
|
2022-09-24 22:18:43 +02:00
|
|
|
static uint64_t s_editCntLast; // Last committed value of global edit counter
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-24 22:18:43 +02:00
|
|
|
AstNode* m_clonep = nullptr; // Pointer to clone/source of node (only for *LAST* cloneTree())
|
2020-04-15 13:58:34 +02:00
|
|
|
static int s_cloneCntGbl; // Count of which userp is set
|
2008-11-25 14:10:41 +01:00
|
|
|
|
|
|
|
|
// This member ordering both allows 64 bit alignment and puts associated data together
|
2022-09-16 01:58:01 +02:00
|
|
|
VNUser m_user1u{0}; // Contains any information the user iteration routine wants
|
2022-01-01 17:46:49 +01:00
|
|
|
uint32_t m_user1Cnt = 0; // Mark of when userp was set
|
|
|
|
|
uint32_t m_user2Cnt = 0; // Mark of when userp was set
|
2022-09-16 01:58:01 +02:00
|
|
|
VNUser m_user2u{0}; // Contains any information the user iteration routine wants
|
|
|
|
|
VNUser m_user3u{0}; // Contains any information the user iteration routine wants
|
2022-01-01 17:46:49 +01:00
|
|
|
uint32_t m_user3Cnt = 0; // Mark of when userp was set
|
|
|
|
|
uint32_t m_user4Cnt = 0; // Mark of when userp was set
|
2022-09-16 01:58:01 +02:00
|
|
|
VNUser m_user4u{0}; // Contains any information the user iteration routine wants
|
|
|
|
|
VNUser m_user5u{0}; // Contains any information the user iteration routine wants
|
2022-01-01 17:46:49 +01:00
|
|
|
uint32_t m_user5Cnt = 0; // Mark of when userp was set
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
2020-04-15 13:58:34 +02:00
|
|
|
void op1p(AstNode* nodep) {
|
|
|
|
|
m_op1p = nodep;
|
|
|
|
|
if (nodep) nodep->m_backp = this;
|
|
|
|
|
}
|
|
|
|
|
void op2p(AstNode* nodep) {
|
|
|
|
|
m_op2p = nodep;
|
|
|
|
|
if (nodep) nodep->m_backp = this;
|
|
|
|
|
}
|
|
|
|
|
void op3p(AstNode* nodep) {
|
|
|
|
|
m_op3p = nodep;
|
|
|
|
|
if (nodep) nodep->m_backp = this;
|
|
|
|
|
}
|
|
|
|
|
void op4p(AstNode* nodep) {
|
|
|
|
|
m_op4p = nodep;
|
|
|
|
|
if (nodep) nodep->m_backp = this;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2015-09-19 01:06:15 +02:00
|
|
|
private:
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNode* cloneTreeIter();
|
|
|
|
|
AstNode* cloneTreeIterList();
|
2022-10-18 23:07:09 +02:00
|
|
|
void checkTreeIter(const AstNode* backp) const VL_MT_SAFE;
|
2020-04-15 13:58:34 +02:00
|
|
|
bool gateTreeIter() const;
|
|
|
|
|
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
|
|
|
|
bool gateOnly);
|
|
|
|
|
void deleteTreeIter();
|
|
|
|
|
void deleteNode();
|
2022-04-22 23:39:45 +02:00
|
|
|
string instanceStr() const;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2016-02-04 02:44:31 +01:00
|
|
|
public:
|
2019-05-19 22:13:13 +02:00
|
|
|
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
|
2011-08-05 03:58:45 +02:00
|
|
|
// cppcheck-suppress functionConst
|
2021-09-25 23:10:57 +02:00
|
|
|
static void debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
protected:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2022-01-02 19:56:40 +01:00
|
|
|
AstNode(VNType t, FileLine* fl);
|
2019-05-19 22:13:13 +02:00
|
|
|
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
|
2006-08-26 13:35:28 +02:00
|
|
|
virtual void cloneRelink() {}
|
2019-11-09 19:33:54 +01:00
|
|
|
void cloneRelinkTree();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
2019-05-19 22:13:13 +02:00
|
|
|
void setOp1p(AstNode* newp); // Set non-list-type op1 to non-list element
|
|
|
|
|
void setOp2p(AstNode* newp); // Set non-list-type op2 to non-list element
|
|
|
|
|
void setOp3p(AstNode* newp); // Set non-list-type op3 to non-list element
|
|
|
|
|
void setOp4p(AstNode* newp); // Set non-list-type op4 to non-list element
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
void addOp1p(AstNode* newp); // Append newp to end of op1
|
|
|
|
|
void addOp2p(AstNode* newp); // Append newp to end of op2
|
|
|
|
|
void addOp3p(AstNode* newp); // Append newp to end of op3
|
|
|
|
|
void addOp4p(AstNode* newp); // Append newp to end of op4
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
|
|
|
|
void setNOp1p(AstNode* newp) { if (newp) setOp1p(newp); }
|
|
|
|
|
void setNOp2p(AstNode* newp) { if (newp) setOp2p(newp); }
|
|
|
|
|
void setNOp3p(AstNode* newp) { if (newp) setOp3p(newp); }
|
|
|
|
|
void setNOp4p(AstNode* newp) { if (newp) setOp4p(newp); }
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
void addNOp1p(AstNode* newp) { if (newp) addOp1p(newp); }
|
|
|
|
|
void addNOp2p(AstNode* newp) { if (newp) addOp2p(newp); }
|
|
|
|
|
void addNOp3p(AstNode* newp) { if (newp) addOp3p(newp); }
|
|
|
|
|
void addNOp4p(AstNode* newp) { if (newp) addOp4p(newp); }
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
void clonep(AstNode* nodep) {
|
|
|
|
|
m_clonep = nodep;
|
|
|
|
|
m_cloneCnt = s_cloneCntGbl;
|
|
|
|
|
}
|
|
|
|
|
static void cloneClearTree() {
|
|
|
|
|
s_cloneCntGbl++;
|
|
|
|
|
UASSERT_STATIC(s_cloneCntGbl, "Rollover");
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// ACCESSORS
|
2022-10-18 23:07:09 +02:00
|
|
|
VNType type() const VL_MT_SAFE { return m_type; }
|
|
|
|
|
const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName
|
|
|
|
|
AstNode* nextp() const VL_MT_SAFE { return m_nextp; }
|
|
|
|
|
AstNode* backp() const VL_MT_SAFE { return m_backp; }
|
2019-12-01 23:19:18 +01:00
|
|
|
AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* op1p() const VL_MT_SAFE { return m_op1p; }
|
|
|
|
|
AstNode* op2p() const VL_MT_SAFE { return m_op2p; }
|
|
|
|
|
AstNode* op3p() const VL_MT_SAFE { return m_op3p; }
|
|
|
|
|
AstNode* op4p() const VL_MT_SAFE { return m_op4p; }
|
|
|
|
|
AstNodeDType* dtypep() const VL_MT_SAFE { return m_dtypep; }
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); }
|
|
|
|
|
AstNode* firstAbovep() const { // Returns nullptr when second or later in list
|
|
|
|
|
return ((backp() && backp()->nextp() != this) ? backp() : nullptr);
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2022-08-12 12:51:25 +02:00
|
|
|
// isFirstInMyListOfStatements(n) -- implemented by child classes:
|
|
|
|
|
// AstNodeBlock, AstCaseItem, AstNodeIf, AstNodeFTask, and possibly others.
|
|
|
|
|
virtual bool isFirstInMyListOfStatements(AstNode* n) const { return false; }
|
|
|
|
|
// isStandaloneBodyStmt == Do we need a ; on generated cpp for this node?
|
|
|
|
|
bool isStandaloneBodyStmt() {
|
|
|
|
|
return (!firstAbovep() // we're 2nd or later in the list, so yes need ;
|
|
|
|
|
|
|
|
|
|
// If we're first in the list, check what backp() thinks of us:
|
|
|
|
|
|| (backp() && backp()->isFirstInMyListOfStatements(this)));
|
|
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
uint8_t brokenState() const VL_MT_SAFE { return m_brokenState; }
|
2021-07-10 17:13:05 +02:00
|
|
|
void brokenState(uint8_t value) { m_brokenState = value; }
|
|
|
|
|
|
|
|
|
|
// Used by AstNode::broken()
|
|
|
|
|
bool brokeExists() const { return V3Broken::isLinkable(this); }
|
|
|
|
|
bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); }
|
|
|
|
|
bool brokeExistsBelow() const { return brokeExists() && !(m_brokenState >> 7); }
|
|
|
|
|
// Note: brokeExistsBelow is not quite precise, as it is true for sibling nodes as well
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// CONSTRUCTORS
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~AstNode() = default;
|
2007-11-02 12:23:03 +01:00
|
|
|
#ifdef VL_LEAK_CHECKS
|
|
|
|
|
static void* operator new(size_t size);
|
|
|
|
|
static void operator delete(void* obj, size_t size);
|
|
|
|
|
#endif
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-07-25 14:32:36 +02:00
|
|
|
// CONSTANTS
|
|
|
|
|
// The following are relative dynamic costs (~ execution cycle count) of various operations.
|
|
|
|
|
// They are used by V3InstCount to estimate the relative execution time of code fragments.
|
|
|
|
|
static constexpr int INSTR_COUNT_BRANCH = 4; // Branch
|
|
|
|
|
static constexpr int INSTR_COUNT_CALL = INSTR_COUNT_BRANCH + 10; // Subroutine call
|
|
|
|
|
static constexpr int INSTR_COUNT_LD = 2; // Load memory
|
|
|
|
|
static constexpr int INSTR_COUNT_INT_MUL = 3; // Integer multiply
|
|
|
|
|
static constexpr int INSTR_COUNT_INT_DIV = 10; // Integer divide
|
|
|
|
|
static constexpr int INSTR_COUNT_DBL = 8; // Convert or do float ops
|
|
|
|
|
static constexpr int INSTR_COUNT_DBL_DIV = 40; // Double divide
|
|
|
|
|
static constexpr int INSTR_COUNT_DBL_TRIG = 200; // Double trigonometric ops
|
|
|
|
|
static constexpr int INSTR_COUNT_STR = 100; // String ops
|
|
|
|
|
static constexpr int INSTR_COUNT_TIME = INSTR_COUNT_CALL + 5; // Determine simulation time
|
|
|
|
|
static constexpr int INSTR_COUNT_PLI = 20; // PLI routines
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// ACCESSORS
|
2022-10-18 23:07:09 +02:00
|
|
|
virtual string name() const VL_MT_SAFE { return ""; }
|
2019-12-24 14:47:30 +01:00
|
|
|
virtual string origName() const { return ""; }
|
2020-04-15 13:58:34 +02:00
|
|
|
virtual void name(const string& name) {
|
|
|
|
|
this->v3fatalSrc("name() called on object without name() method");
|
|
|
|
|
}
|
2017-10-06 13:33:52 +02:00
|
|
|
virtual void tag(const string& text) {}
|
|
|
|
|
virtual string tag() const { return ""; }
|
2006-08-26 13:35:28 +02:00
|
|
|
virtual string verilogKwd() const { return ""; }
|
2022-10-18 23:07:09 +02:00
|
|
|
string nameProtect() const VL_MT_SAFE; // Name with --protect-id applied
|
2019-12-24 14:47:30 +01:00
|
|
|
string origNameProtect() const; // origName with --protect-id applied
|
2019-05-19 22:13:13 +02:00
|
|
|
string shortName() const; // Name with __PVT__ removed for concatenating scopes
|
|
|
|
|
static string dedotName(const string& namein); // Name with dots removed
|
|
|
|
|
static string prettyName(const string& namein); // Name for printing out to the user
|
2019-07-12 04:09:30 +02:00
|
|
|
static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors)
|
2022-08-30 05:50:32 +02:00
|
|
|
return std::string{"'"} + prettyName(namein) + "'";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
static string
|
|
|
|
|
encodeName(const string& namein); // Encode user name into internal C representation
|
2022-03-27 21:27:40 +02:00
|
|
|
static string encodeNumber(int64_t num); // Encode number into internal C representation
|
2018-10-15 00:39:33 +02:00
|
|
|
static string vcdName(const string& namein); // Name for printing out to vcd files
|
2022-10-18 23:07:09 +02:00
|
|
|
string prettyName() const VL_MT_SAFE { return prettyName(name()); }
|
2019-07-12 04:09:30 +02:00
|
|
|
string prettyNameQ() const { return prettyNameQ(name()); }
|
2020-01-26 19:21:25 +01:00
|
|
|
string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name)
|
2020-04-15 13:58:34 +02:00
|
|
|
virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
|
2022-10-18 23:07:09 +02:00
|
|
|
FileLine* fileline() const VL_MT_SAFE { return m_fileline; }
|
2019-05-19 22:13:13 +02:00
|
|
|
void fileline(FileLine* fl) { m_fileline = fl; }
|
2022-09-16 14:17:38 +02:00
|
|
|
inline bool width1() const;
|
|
|
|
|
inline int widthInstrs() const;
|
2021-07-10 09:01:58 +02:00
|
|
|
void didWidth(bool flag) { m_flags.didWidth = flag; }
|
|
|
|
|
bool didWidth() const { return m_flags.didWidth; }
|
2020-04-15 13:58:34 +02:00
|
|
|
bool didWidthAndSet() {
|
|
|
|
|
if (didWidth()) return true;
|
|
|
|
|
didWidth(true);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-07-10 09:01:58 +02:00
|
|
|
bool doingWidth() const { return m_flags.doingWidth; }
|
|
|
|
|
void doingWidth(bool flag) { m_flags.doingWidth = flag; }
|
2022-10-18 23:07:09 +02:00
|
|
|
bool protect() const VL_MT_SAFE { return m_flags.protect; }
|
2021-07-10 09:01:58 +02:00
|
|
|
void protect(bool flag) { m_flags.protect = flag; }
|
2012-04-29 16:14:13 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// TODO stomp these width functions out, and call via dtypep() instead
|
2022-10-18 23:07:09 +02:00
|
|
|
inline int width() const VL_MT_SAFE;
|
2022-09-16 14:17:38 +02:00
|
|
|
inline int widthMin() const;
|
2020-04-15 13:58:34 +02:00
|
|
|
int widthMinV() const {
|
|
|
|
|
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
int widthWords() const { return VL_WORDS_I(width()); }
|
2022-10-18 23:07:09 +02:00
|
|
|
bool isQuad() const VL_MT_SAFE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
|
|
|
|
bool isWide() const VL_MT_SAFE { return (width() > VL_QUADSIZE); }
|
2022-09-16 14:17:38 +02:00
|
|
|
inline bool isDouble() const;
|
|
|
|
|
inline bool isSigned() const;
|
|
|
|
|
inline bool isString() const;
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format off
|
2022-10-18 23:07:09 +02:00
|
|
|
VNUser user1u() const VL_MT_SAFE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slows things down measurably, so disabled by default
|
2022-01-02 19:56:40 +01:00
|
|
|
//UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy");
|
2022-09-16 01:58:01 +02:00
|
|
|
return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0});
|
2008-11-21 21:50:33 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* user1p() const VL_MT_SAFE { return user1u().toNodep(); }
|
2022-01-02 19:56:40 +01:00
|
|
|
void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user1p(void* userp) { user1u(VNUser{userp}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user1() const { return user1u().toInt(); }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user1(int val) { user1u(VNUser{val}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user1Inc(int val=1) { int v=user1(); user1(v+val); return v; }
|
|
|
|
|
int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc()
|
2022-01-02 19:56:40 +01:00
|
|
|
static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
VNUser user2u() const VL_MT_SAFE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slows things down measurably, so disabled by default
|
2022-01-02 19:56:40 +01:00
|
|
|
//UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy");
|
2022-09-16 01:58:01 +02:00
|
|
|
return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0});
|
2016-11-27 15:40:12 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* user2p() const VL_MT_SAFE { return user2u().toNodep(); }
|
2022-01-02 19:56:40 +01:00
|
|
|
void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user2p(void* userp) { user2u(VNUser{userp}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user2() const { return user2u().toInt(); }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user2(int val) { user2u(VNUser{val}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user2Inc(int val=1) { int v=user2(); user2(v+val); return v; }
|
|
|
|
|
int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc()
|
2022-01-02 19:56:40 +01:00
|
|
|
static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
VNUser user3u() const VL_MT_SAFE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slows things down measurably, so disabled by default
|
2022-01-02 19:56:40 +01:00
|
|
|
//UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy");
|
2022-09-16 01:58:01 +02:00
|
|
|
return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0});
|
2016-11-27 15:40:12 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* user3p() const VL_MT_SAFE { return user3u().toNodep(); }
|
2022-01-02 19:56:40 +01:00
|
|
|
void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user3p(void* userp) { user3u(VNUser{userp}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user3() const { return user3u().toInt(); }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user3(int val) { user3u(VNUser{val}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user3Inc(int val=1) { int v=user3(); user3(v+val); return v; }
|
|
|
|
|
int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc()
|
2022-01-02 19:56:40 +01:00
|
|
|
static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
VNUser user4u() const VL_MT_SAFE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slows things down measurably, so disabled by default
|
2022-01-02 19:56:40 +01:00
|
|
|
//UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy");
|
2022-09-16 01:58:01 +02:00
|
|
|
return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0});
|
2016-11-27 15:40:12 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* user4p() const VL_MT_SAFE { return user4u().toNodep(); }
|
2022-01-02 19:56:40 +01:00
|
|
|
void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user4p(void* userp) { user4u(VNUser{userp}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user4() const { return user4u().toInt(); }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user4(int val) { user4u(VNUser{val}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user4Inc(int val=1) { int v=user4(); user4(v+val); return v; }
|
|
|
|
|
int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
|
2022-01-02 19:56:40 +01:00
|
|
|
static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2022-10-18 23:07:09 +02:00
|
|
|
VNUser user5u() const VL_MT_SAFE {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Slows things down measurably, so disabled by default
|
2022-01-02 19:56:40 +01:00
|
|
|
//UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy");
|
2022-09-16 01:58:01 +02:00
|
|
|
return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0});
|
2016-11-27 15:40:12 +01:00
|
|
|
}
|
2022-10-18 23:07:09 +02:00
|
|
|
AstNode* user5p() const VL_MT_SAFE { return user5u().toNodep(); }
|
2022-01-02 19:56:40 +01:00
|
|
|
void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user5p(void* userp) { user5u(VNUser{userp}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user5() const { return user5u().toInt(); }
|
2022-09-16 01:58:01 +02:00
|
|
|
void user5(int val) { user5u(VNUser{val}); }
|
2019-05-19 22:13:13 +02:00
|
|
|
int user5Inc(int val=1) { int v=user5(); user5(v+val); return v; }
|
|
|
|
|
int user5SetOnce() { int v=user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc()
|
2022-01-02 19:56:40 +01:00
|
|
|
static void user5ClearTree() { VNUser5InUse::clear(); } // Clear userp()'s across the entire tree
|
2020-04-15 13:58:34 +02:00
|
|
|
// clang-format on
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2022-09-24 22:18:43 +02:00
|
|
|
#ifdef VL_DEBUG
|
2022-03-27 21:27:40 +02:00
|
|
|
uint64_t editCount() const { return m_editCount; }
|
2020-04-15 13:58:34 +02:00
|
|
|
void editCountInc() {
|
|
|
|
|
m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##"
|
|
|
|
|
}
|
2022-09-24 22:18:43 +02:00
|
|
|
#else
|
|
|
|
|
void editCountInc() { ++s_editCntGbl; }
|
|
|
|
|
#endif
|
2022-10-18 23:07:09 +02:00
|
|
|
static uint64_t editCountLast() VL_MT_SAFE { return s_editCntLast; }
|
|
|
|
|
static uint64_t editCountGbl() VL_MT_SAFE { return s_editCntGbl; }
|
2019-05-19 22:13:13 +02:00
|
|
|
static void editCountSetLast() { s_editCntLast = editCountGbl(); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// ACCESSORS for specific types
|
2020-08-15 16:12:55 +02:00
|
|
|
// Alas these can't be virtual or they break when passed a nullptr
|
2022-09-16 14:17:38 +02:00
|
|
|
inline bool isZero() const;
|
|
|
|
|
inline bool isOne() const;
|
|
|
|
|
inline bool isNeqZero() const;
|
|
|
|
|
inline bool isAllOnes() const;
|
|
|
|
|
inline bool isAllOnesV() const; // Verilog width rules apply
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2011-12-01 01:32:33 +01:00
|
|
|
// METHODS - data type changes especially for initial creation
|
2020-04-15 13:58:34 +02:00
|
|
|
void dtypep(AstNodeDType* nodep) {
|
|
|
|
|
if (m_dtypep != nodep) {
|
|
|
|
|
m_dtypep = nodep;
|
|
|
|
|
editCountInc();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-02 04:14:46 +01:00
|
|
|
void dtypeFrom(const AstNode* fromp) {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (fromp) dtypep(fromp->dtypep());
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
void dtypeChgSigned(bool flag = true);
|
2019-05-19 22:13:13 +02:00
|
|
|
void dtypeChgWidth(int width, int widthMin);
|
2020-04-20 03:19:09 +02:00
|
|
|
void dtypeChgWidthSigned(int width, int widthMin, VSigning numeric);
|
|
|
|
|
void dtypeSetBitUnsized(int width, int widthMin, VSigning numeric) {
|
2020-04-15 13:58:34 +02:00
|
|
|
dtypep(findBitDType(width, widthMin, numeric));
|
|
|
|
|
}
|
2020-04-20 03:19:09 +02:00
|
|
|
void dtypeSetBitSized(int width, VSigning numeric) {
|
2020-04-15 13:58:34 +02:00
|
|
|
dtypep(findBitDType(width, width, numeric)); // Since sized, widthMin is width
|
|
|
|
|
}
|
2020-04-20 03:19:09 +02:00
|
|
|
void dtypeSetLogicUnsized(int width, int widthMin, VSigning numeric) {
|
2020-04-15 13:58:34 +02:00
|
|
|
dtypep(findLogicDType(width, widthMin, numeric));
|
|
|
|
|
}
|
2020-04-20 03:19:09 +02:00
|
|
|
void dtypeSetLogicSized(int width, VSigning numeric) {
|
2020-04-15 13:58:34 +02:00
|
|
|
dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width
|
|
|
|
|
}
|
2020-11-29 14:23:36 +01:00
|
|
|
void dtypeSetBit() { dtypep(findBitDType()); }
|
2020-04-15 13:58:34 +02:00
|
|
|
void dtypeSetDouble() { dtypep(findDoubleDType()); }
|
|
|
|
|
void dtypeSetString() { dtypep(findStringDType()); }
|
|
|
|
|
void dtypeSetSigned32() { dtypep(findSigned32DType()); }
|
|
|
|
|
void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate
|
|
|
|
|
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
|
2021-08-28 23:23:35 +02:00
|
|
|
void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
|
2019-12-01 17:52:48 +01:00
|
|
|
void dtypeSetVoid() { dtypep(findVoidDType()); }
|
2012-05-10 04:12:57 +02:00
|
|
|
|
|
|
|
|
// Data type locators
|
2022-07-18 18:58:55 +02:00
|
|
|
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
|
|
|
|
|
AstNodeDType* findDoubleDType() const { return findBasicDType(VBasicDTypeKwd::DOUBLE); }
|
|
|
|
|
AstNodeDType* findStringDType() const { return findBasicDType(VBasicDTypeKwd::STRING); }
|
|
|
|
|
AstNodeDType* findSigned32DType() const { return findBasicDType(VBasicDTypeKwd::INTEGER); }
|
|
|
|
|
AstNodeDType* findUInt32DType() const { return findBasicDType(VBasicDTypeKwd::UINT32); }
|
|
|
|
|
AstNodeDType* findUInt64DType() const { return findBasicDType(VBasicDTypeKwd::UINT64); }
|
|
|
|
|
AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); }
|
2021-08-28 23:23:35 +02:00
|
|
|
AstNodeDType* findEmptyQueueDType() const;
|
2019-12-01 17:52:48 +01:00
|
|
|
AstNodeDType* findVoidDType() const;
|
2020-11-01 16:56:07 +01:00
|
|
|
AstNodeDType* findQueueIndexDType() const;
|
2020-04-20 03:19:09 +02:00
|
|
|
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
|
|
|
|
|
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
|
2020-04-04 04:31:54 +02:00
|
|
|
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
|
2020-04-20 03:19:09 +02:00
|
|
|
VSigning numeric) const;
|
|
|
|
|
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric) const;
|
2022-01-02 19:56:40 +01:00
|
|
|
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
|
2021-07-25 19:38:27 +02:00
|
|
|
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
2011-12-01 01:32:33 +01:00
|
|
|
|
2011-12-01 00:50:21 +01:00
|
|
|
// METHODS - dump and error
|
2022-10-18 23:07:09 +02:00
|
|
|
void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE;
|
|
|
|
|
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE;
|
2019-06-22 23:01:39 +02:00
|
|
|
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
|
|
|
|
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
|
|
|
|
string warnMore() const { return fileline()->warnMore(); }
|
2019-07-12 01:15:40 +02:00
|
|
|
string warnOther() const { return fileline()->warnOther(); }
|
2019-06-22 23:01:39 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
virtual void dump(std::ostream& str = std::cout) const;
|
2020-11-25 00:35:12 +01:00
|
|
|
static void dumpGdb(const AstNode* nodep); // For GDB only
|
2019-05-19 22:13:13 +02:00
|
|
|
void dumpGdbHeader() const;
|
2011-12-01 00:50:21 +01:00
|
|
|
|
|
|
|
|
// METHODS - Tree modifications
|
2020-04-15 13:58:34 +02:00
|
|
|
// Returns nodep, adds newp to end of nodep's list
|
2022-08-29 15:26:00 +02:00
|
|
|
template <typename T_NodeResult, typename T_NodeNext>
|
|
|
|
|
static T_NodeResult* addNext(T_NodeResult* nodep, T_NodeNext* newp) {
|
|
|
|
|
static_assert(std::is_base_of<AstNode, T_NodeResult>::value,
|
|
|
|
|
"'T_NodeResult' must be a subtype of AstNode");
|
|
|
|
|
static_assert(std::is_base_of<T_NodeResult, T_NodeNext>::value,
|
|
|
|
|
"'T_NodeNext' must be a subtype of 'T_NodeResult'");
|
|
|
|
|
return static_cast<T_NodeResult*>(addNext<AstNode, AstNode>(nodep, newp));
|
|
|
|
|
}
|
|
|
|
|
inline AstNode* addNext(AstNode* newp);
|
2022-09-17 14:48:51 +02:00
|
|
|
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
2019-05-19 22:13:13 +02:00
|
|
|
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
|
|
|
|
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
2022-01-02 16:32:35 +01:00
|
|
|
AstNode* unlinkFrBack(VNRelinker* linkerp
|
2020-08-15 16:12:55 +02:00
|
|
|
= nullptr); // Unlink this from whoever points to it.
|
2018-03-10 22:32:04 +01:00
|
|
|
// Unlink this from whoever points to it, keep entire next list with unlinked node
|
2022-01-02 16:32:35 +01:00
|
|
|
AstNode* unlinkFrBackWithNext(VNRelinker* linkerp = nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
void swapWith(AstNode* bp);
|
2022-01-02 16:32:35 +01:00
|
|
|
void relink(VNRelinker* linkerp); // Generally use linker->relink() instead
|
2019-05-19 22:13:13 +02:00
|
|
|
void cloneRelinkNode() { cloneRelink(); }
|
2009-10-09 02:42:45 +02:00
|
|
|
// Iterate and insert - assumes tree format
|
2020-04-15 13:58:34 +02:00
|
|
|
virtual void addNextStmt(AstNode* newp,
|
|
|
|
|
AstNode* belowp); // When calling, "this" is second argument
|
|
|
|
|
virtual void addBeforeStmt(AstNode* newp,
|
|
|
|
|
AstNode* belowp); // When calling, "this" is second argument
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS - Iterate on a tree
|
2020-08-15 16:12:55 +02:00
|
|
|
// Clone or return nullptr if nullptr
|
2019-11-09 19:33:54 +01:00
|
|
|
static AstNode* cloneTreeNull(AstNode* nodep, bool cloneNextLink) {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-11-09 19:33:54 +01:00
|
|
|
AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep
|
2019-05-19 22:13:13 +02:00
|
|
|
bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable?
|
2022-09-16 14:17:38 +02:00
|
|
|
inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p?
|
2020-04-15 13:58:34 +02:00
|
|
|
// Does tree of this == node2p?, not allowing non-isGateOptimizable
|
2022-09-16 14:17:38 +02:00
|
|
|
inline bool sameGateTree(const AstNode* node2p) const;
|
2019-05-19 22:13:13 +02:00
|
|
|
void deleteTree(); // Always deletes the next link
|
2022-10-18 23:07:09 +02:00
|
|
|
void checkTree() const VL_MT_SAFE {
|
2022-09-21 16:24:17 +02:00
|
|
|
if (v3Global.opt.debugCheck()) checkTreeIter(backp());
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
void checkIter() const;
|
2020-04-15 13:58:34 +02:00
|
|
|
void dumpPtrs(std::ostream& os = std::cout) const;
|
|
|
|
|
void dumpTree(std::ostream& os = std::cout, const string& indent = " ",
|
|
|
|
|
int maxDepth = 0) const;
|
|
|
|
|
void dumpTree(const string& indent, int maxDepth = 0) const {
|
|
|
|
|
dumpTree(cout, indent, maxDepth);
|
|
|
|
|
}
|
2020-11-25 00:35:12 +01:00
|
|
|
static void dumpTreeGdb(const AstNode* nodep); // For GDB only
|
2020-04-15 13:58:34 +02:00
|
|
|
void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ",
|
|
|
|
|
int maxDepth = 0) const;
|
2020-11-12 01:00:10 +01:00
|
|
|
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
|
|
|
|
|
bool doCheck = true);
|
2020-11-25 00:35:12 +01:00
|
|
|
static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
|
2022-10-01 17:05:33 +02:00
|
|
|
void dumpTreeDot(std::ostream& os = std::cout) const;
|
|
|
|
|
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS - queries
|
2020-04-15 13:58:34 +02:00
|
|
|
// Changes control flow, disable some optimizations
|
|
|
|
|
virtual bool isBrancher() const { return false; }
|
|
|
|
|
// Else a AstTime etc that can't be pushed out
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
virtual bool isGateOptimizable() const { return !isTimingControl(); }
|
2018-03-10 22:32:04 +01:00
|
|
|
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
|
|
|
|
virtual bool isGateDedupable() const { return isGateOptimizable(); }
|
2020-04-15 13:58:34 +02:00
|
|
|
// Else creates output or exits, etc, not unconsumed
|
|
|
|
|
virtual bool isOutputter() const { return false; }
|
2020-05-25 21:34:24 +02:00
|
|
|
// Else a AstTime etc which output can't be predicted from input
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
virtual bool isPredictOptimizable() const { return !isTimingControl(); }
|
2020-05-25 21:34:24 +02:00
|
|
|
// Else a $display, etc, that must be ordered with other displays
|
|
|
|
|
virtual bool isPure() const { return true; }
|
|
|
|
|
// Else a AstTime etc that can't be substituted out
|
|
|
|
|
virtual bool isSubstOptimizable() const { return true; }
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
// An event control, delay, wait, etc.
|
|
|
|
|
virtual bool isTimingControl() const { return false; }
|
2019-05-19 22:13:13 +02:00
|
|
|
// isUnlikely handles $stop or similar statement which means an above IF
|
|
|
|
|
// statement is unlikely to be taken
|
2018-03-10 22:32:04 +01:00
|
|
|
virtual bool isUnlikely() const { return false; }
|
2019-05-19 22:13:13 +02:00
|
|
|
virtual int instrCount() const { return 0; }
|
2017-10-28 16:26:19 +02:00
|
|
|
virtual bool same(const AstNode*) const { return true; }
|
2020-04-15 13:58:34 +02:00
|
|
|
// Iff has a data type; dtype() must be non null
|
2022-10-18 23:07:09 +02:00
|
|
|
virtual bool hasDType() const VL_MT_SAFE { return false; }
|
2020-04-15 13:58:34 +02:00
|
|
|
// Iff has a non-null childDTypep(), as generic node function
|
2020-08-15 16:12:55 +02:00
|
|
|
virtual AstNodeDType* getChildDTypep() const { return nullptr; }
|
2020-06-08 12:47:18 +02:00
|
|
|
// Iff has a non-null child2DTypep(), as generic node function
|
2020-08-15 16:12:55 +02:00
|
|
|
virtual AstNodeDType* getChild2DTypep() const { return nullptr; }
|
2018-03-10 22:32:04 +01:00
|
|
|
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
2022-10-18 23:07:09 +02:00
|
|
|
virtual bool maybePointedTo() const VL_MT_SAFE { return false; }
|
2021-12-13 00:10:52 +01:00
|
|
|
// Don't reclaim this node in V3Dead
|
|
|
|
|
virtual bool undead() const { return false; }
|
|
|
|
|
// Check if node is consistent, return nullptr if ok, else reason string
|
2020-08-15 16:12:55 +02:00
|
|
|
virtual const char* broken() const { return nullptr; }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// INVOKERS
|
2022-01-02 19:56:40 +01:00
|
|
|
virtual void accept(VNVisitor& v) = 0;
|
2018-05-11 02:55:37 +02:00
|
|
|
|
|
|
|
|
protected:
|
2022-01-02 19:56:40 +01:00
|
|
|
// All VNVisitor related functions are called as methods off the visitor
|
|
|
|
|
friend class VNVisitor;
|
|
|
|
|
// Use instead VNVisitor::iterateChildren
|
|
|
|
|
void iterateChildren(VNVisitor& v);
|
|
|
|
|
// Use instead VNVisitor::iterateChildrenBackwards
|
|
|
|
|
void iterateChildrenBackwards(VNVisitor& v);
|
|
|
|
|
// Use instead VNVisitor::iterateChildrenConst
|
|
|
|
|
void iterateChildrenConst(VNVisitor& v);
|
|
|
|
|
// Use instead VNVisitor::iterateAndNextNull
|
|
|
|
|
void iterateAndNext(VNVisitor& v);
|
|
|
|
|
// Use instead VNVisitor::iterateAndNextConstNull
|
|
|
|
|
void iterateAndNextConst(VNVisitor& v);
|
|
|
|
|
// Use instead VNVisitor::iterateSubtreeReturnEdits
|
|
|
|
|
AstNode* iterateSubtreeReturnEdits(VNVisitor& v);
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2018-05-11 02:55:37 +02:00
|
|
|
private:
|
2022-01-02 19:56:40 +01:00
|
|
|
void iterateListBackwards(VNVisitor& v);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-10-16 20:18:06 +02:00
|
|
|
// For internal use only.
|
2022-01-09 23:34:10 +01:00
|
|
|
// Note: specializations for particular node types are provided by 'astgen'
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T>
|
|
|
|
|
inline static bool privateTypeTest(const AstNode* nodep);
|
2020-01-23 01:07:48 +01:00
|
|
|
|
2022-01-09 23:34:10 +01:00
|
|
|
// For internal use only.
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename TargetType, typename DeclType>
|
|
|
|
|
constexpr static bool uselessCast() {
|
2021-10-22 18:36:58 +02:00
|
|
|
using NonRef = typename std::remove_reference<DeclType>::type;
|
|
|
|
|
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
|
|
|
|
using NonCV = typename std::remove_cv<NonPtr>::type;
|
|
|
|
|
return std::is_base_of<TargetType, NonCV>::value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 23:34:10 +01:00
|
|
|
// For internal use only.
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename TargetType, typename DeclType>
|
|
|
|
|
constexpr static bool impossibleCast() {
|
2021-10-22 18:36:58 +02:00
|
|
|
using NonRef = typename std::remove_reference<DeclType>::type;
|
|
|
|
|
using NonPtr = typename std::remove_pointer<NonRef>::type;
|
|
|
|
|
using NonCV = typename std::remove_cv<NonPtr>::type;
|
|
|
|
|
return !std::is_base_of<NonCV, TargetType>::value;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-16 20:18:06 +02:00
|
|
|
public:
|
|
|
|
|
// For use via the VN_IS macro only
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T, typename E>
|
2022-10-18 23:07:09 +02:00
|
|
|
static bool privateIs(const AstNode* nodep) VL_MT_SAFE {
|
2021-10-22 18:36:58 +02:00
|
|
|
static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
|
|
|
|
|
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
|
2021-10-16 20:18:06 +02:00
|
|
|
return nodep && privateTypeTest<T>(nodep);
|
|
|
|
|
}
|
2021-10-22 16:15:42 +02:00
|
|
|
|
2021-10-16 20:18:06 +02:00
|
|
|
// For use via the VN_CAST macro only
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T, typename E>
|
2022-10-18 23:07:09 +02:00
|
|
|
static T* privateCast(AstNode* nodep) VL_MT_SAFE {
|
2021-10-22 18:36:58 +02:00
|
|
|
static_assert(!uselessCast<T, E>(),
|
|
|
|
|
"Unnecessary VN_CAST, node known to have target type.");
|
|
|
|
|
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
|
|
|
|
|
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
|
2021-10-16 20:18:06 +02:00
|
|
|
}
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T, typename E>
|
2022-10-18 23:07:09 +02:00
|
|
|
static const T* privateCast(const AstNode* nodep) VL_MT_SAFE {
|
2021-10-22 18:36:58 +02:00
|
|
|
static_assert(!uselessCast<T, E>(),
|
2021-10-22 16:15:42 +02:00
|
|
|
"Unnecessary VN_CAST, node known to have target type.");
|
|
|
|
|
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
|
2021-10-22 18:36:58 +02:00
|
|
|
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
|
2021-10-16 20:18:06 +02:00
|
|
|
}
|
2021-10-22 16:15:42 +02:00
|
|
|
|
2021-10-16 20:29:38 +02:00
|
|
|
// For use via the VN_AS macro only
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T, typename E>
|
2022-10-18 23:07:09 +02:00
|
|
|
static T* privateAs(AstNode* nodep) VL_MT_SAFE {
|
2021-10-22 18:36:58 +02:00
|
|
|
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
|
|
|
|
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
2021-10-16 20:29:38 +02:00
|
|
|
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
|
|
|
|
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
|
|
|
|
|
<< "'");
|
|
|
|
|
return reinterpret_cast<T*>(nodep);
|
|
|
|
|
}
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T, typename E>
|
2022-10-18 23:07:09 +02:00
|
|
|
static const T* privateAs(const AstNode* nodep) VL_MT_SAFE {
|
2021-10-22 16:15:42 +02:00
|
|
|
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
|
|
|
|
|
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
|
2021-10-16 20:29:38 +02:00
|
|
|
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
|
|
|
|
|
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
|
|
|
|
|
<< "'");
|
|
|
|
|
return reinterpret_cast<const T*>(nodep);
|
|
|
|
|
}
|
2022-01-09 23:34:10 +01:00
|
|
|
|
|
|
|
|
// Predicate that returns true if the given 'nodep' might have a descendant of type 'T_Node'.
|
|
|
|
|
// This is conservative and is used to speed up traversals.
|
2022-07-31 19:13:55 +02:00
|
|
|
// Note: specializations for particular node types are provided below
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T_Node>
|
|
|
|
|
static bool mayBeUnder(const AstNode* nodep) {
|
2022-01-09 23:34:10 +01:00
|
|
|
static_assert(!std::is_const<T_Node>::value,
|
|
|
|
|
"Type parameter 'T_Node' should not be const qualified");
|
|
|
|
|
static_assert(std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Type parameter 'T_Node' must be a subtype of AstNode");
|
2022-07-31 19:13:55 +02:00
|
|
|
return true;
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
// Predicate that is true for node subtypes 'T_Node' that do not have any children
|
|
|
|
|
// This is conservative and is used to speed up traversals.
|
|
|
|
|
// Note: specializations for particular node types are provided below
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T_Node>
|
|
|
|
|
static constexpr bool isLeaf() {
|
2022-07-31 19:13:55 +02:00
|
|
|
static_assert(!std::is_const<T_Node>::value,
|
|
|
|
|
"Type parameter 'T_Node' should not be const qualified");
|
|
|
|
|
static_assert(std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Type parameter 'T_Node' must be a subtype of AstNode");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-04-29 16:44:22 +02:00
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
private:
|
|
|
|
|
// Using std::conditional for const correctness in the public 'foreach' functions
|
|
|
|
|
template <typename T_Arg>
|
|
|
|
|
using ConstCorrectAstNode =
|
|
|
|
|
typename std::conditional<std::is_const<T_Arg>::value, const AstNode, AstNode>::type;
|
2022-04-29 16:44:22 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename T_Arg, typename Callable>
|
|
|
|
|
inline static void foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f,
|
|
|
|
|
bool visitNext);
|
2022-04-29 16:44:22 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename T_Arg, bool Default, typename Callable>
|
|
|
|
|
inline static bool predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p);
|
2022-04-29 16:44:22 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename T_Callable>
|
|
|
|
|
struct Arg0NoPointerNoCV final {
|
|
|
|
|
using Traits = FunctionTraits<T_Callable>;
|
|
|
|
|
using T_Arg0 = typename Traits::template arg<0>::type;
|
|
|
|
|
using T_Arg0NoPtr = typename std::remove_pointer<T_Arg0>::type;
|
|
|
|
|
using type = typename std::remove_cv<T_Arg0NoPtr>::type;
|
|
|
|
|
};
|
2022-04-29 16:44:22 +02:00
|
|
|
|
|
|
|
|
public:
|
2022-10-20 14:48:44 +02:00
|
|
|
// Given a callable 'f' that takes a single argument of some AstNode subtype 'T_Node', traverse
|
|
|
|
|
// the tree rooted at this node, and call 'f' in pre-order on each node that is of type
|
|
|
|
|
// 'T_Node'. The node passed to the callable 'f' can be removed or replaced, but other editing
|
2022-07-31 19:13:55 +02:00
|
|
|
// of the iterated tree is not safe. Prefer 'foreach' over simple VNVisitor that only needs to
|
|
|
|
|
// handle a single (or a few) node types, as it's easier to write, but more importantly, the
|
2022-10-20 14:48:44 +02:00
|
|
|
// dispatch to the callable in 'foreach' should be completely predictable by branch target
|
|
|
|
|
// caches in modern CPUs, while it is basically unpredictable for VNVisitor.
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
void foreach(Callable&& f) {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable<Callable, T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Callable 'f' must have a signature compatible with 'void(T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
foreachImpl<T_Node>(this, f, /* visitNext: */ false);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Same as above, but for 'const' nodes
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename Callable>
|
|
|
|
|
void foreach(Callable&& f) const {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
foreachImpl<const T_Node>(this, f, /* visitNext: */ false);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Same as 'foreach' but also traverses 'this->nextp()' transitively
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
void foreachAndNext(Callable&& f) {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable<Callable, T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Callable 'f' must have a signature compatible with 'void(T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
foreachImpl<T_Node>(this, f, /* visitNext: */ true);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Same as above, but for 'const' nodes
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
void foreachAndNext(Callable&& f) const {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
foreachImpl<const T_Node>(this, f, /* visitNext: */ true);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Given a predicate 'p' that takes a single argument of some AstNode subtype 'T_Node', return
|
|
|
|
|
// true if and only if there exists a node of type 'T_Node' in the tree rooted at this node,
|
|
|
|
|
// that satisfies the predicate 'p'. Returns false if no node of type 'T_Node' is present.
|
|
|
|
|
// Traversal is performed in some arbitrary order and is terminated as soon as the result can
|
|
|
|
|
// be determined.
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
bool exists(Callable&& p) {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
return predicateImpl<T_Node, /* Default: */ false>(this, p);
|
2022-04-29 16:44:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Same as above, but for 'const' nodes
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename Callable>
|
|
|
|
|
bool exists(Callable&& p) const {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
return predicateImpl<const T_Node, /* Default: */ false>(this, p);
|
2022-04-29 16:44:22 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Given a predicate 'p' that takes a single argument of some AstNode subtype 'T_Node', return
|
|
|
|
|
// true if and only if all nodes of type 'T_Node' in the tree rooted at this node satisfy the
|
|
|
|
|
// predicate 'p'. Returns true if no node of type 'T_Node' is present. Traversal is performed
|
|
|
|
|
// in some arbitrary order and is terminated as soon as the result can be determined.
|
|
|
|
|
template <typename Callable>
|
|
|
|
|
bool forall(Callable&& p) {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
return predicateImpl<T_Node, /* Default: */ true>(this, p);
|
2022-04-29 16:44:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Same as above, but for 'const' nodes
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename Callable>
|
|
|
|
|
bool forall(Callable&& p) const {
|
|
|
|
|
using T_Node = typename Arg0NoPointerNoCV<Callable>::type;
|
|
|
|
|
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value
|
|
|
|
|
&& std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
|
|
|
|
|
"with 'T_Node' being a subtype of 'AstNode'");
|
2022-07-31 19:13:55 +02:00
|
|
|
return predicateImpl<const T_Node, /* Default: */ true>(this, p);
|
2022-04-29 16:44:22 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-09 23:34:10 +01:00
|
|
|
int nodeCount() const {
|
|
|
|
|
// TODO: this should really return size_t, but need to fix use sites
|
|
|
|
|
int count = 0;
|
2022-10-20 14:48:44 +02:00
|
|
|
this->foreach([&count](const AstNode*) { ++count; });
|
2022-01-09 23:34:10 +01:00
|
|
|
return count;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
2022-08-29 15:26:00 +02:00
|
|
|
// Forward declarations of specializations defined in V3Ast.cpp
|
|
|
|
|
template <>
|
|
|
|
|
AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp);
|
2022-09-17 14:48:51 +02:00
|
|
|
|
|
|
|
|
// Inline method implementations
|
|
|
|
|
AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); }
|
2022-08-29 15:26:00 +02:00
|
|
|
|
2022-01-09 23:34:10 +01:00
|
|
|
// Specialisations of privateTypeTest
|
2022-10-04 12:03:41 +02:00
|
|
|
#include "V3Ast__gen_type_tests.h" // From ./astgen
|
2020-01-23 01:07:48 +01:00
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
// Specializations of AstNode::mayBeUnder
|
2022-08-05 11:56:57 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) {
|
2022-10-12 11:19:21 +02:00
|
|
|
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeExpr);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
2022-08-05 11:56:57 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) {
|
2022-10-12 11:19:21 +02:00
|
|
|
return !VN_IS(nodep, NodeExpr);
|
2022-01-09 23:34:10 +01:00
|
|
|
}
|
2022-08-05 11:56:57 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) {
|
2022-07-31 19:36:56 +02:00
|
|
|
if (VN_IS(nodep, VarScope)) return false; // Should not nest
|
|
|
|
|
if (VN_IS(nodep, Var)) return false;
|
|
|
|
|
if (VN_IS(nodep, Active)) return false;
|
|
|
|
|
if (VN_IS(nodep, NodeStmt)) return false;
|
2022-10-12 11:19:21 +02:00
|
|
|
if (VN_IS(nodep, NodeExpr)) return false;
|
2022-07-31 19:36:56 +02:00
|
|
|
return true;
|
2022-02-11 11:46:02 +01:00
|
|
|
}
|
2022-08-05 11:56:57 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstExecGraph>(const AstNode* nodep) {
|
2022-04-10 12:37:41 +02:00
|
|
|
if (VN_IS(nodep, ExecGraph)) return false; // Should not nest
|
|
|
|
|
if (VN_IS(nodep, NodeStmt)) return false; // Should be directly under CFunc
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-08-05 13:15:59 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstActive>(const AstNode* nodep) {
|
2022-05-15 17:03:32 +02:00
|
|
|
return !VN_IS(nodep, Active); // AstActives do not nest
|
|
|
|
|
}
|
2022-08-05 13:15:59 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstScope>(const AstNode* nodep) {
|
2022-05-15 17:03:32 +02:00
|
|
|
return !VN_IS(nodep, Scope); // AstScopes do not nest
|
|
|
|
|
}
|
2022-08-05 13:15:59 +02:00
|
|
|
template <>
|
|
|
|
|
inline bool AstNode::mayBeUnder<AstSenTree>(const AstNode* nodep) {
|
2022-05-15 17:03:32 +02:00
|
|
|
return !VN_IS(nodep, SenTree); // AstSenTree do not nest
|
|
|
|
|
}
|
2022-01-09 23:34:10 +01:00
|
|
|
|
2022-07-31 19:13:55 +02:00
|
|
|
// Specializations of AstNode::isLeaf
|
2022-08-05 11:56:57 +02:00
|
|
|
template <>
|
|
|
|
|
constexpr bool AstNode::isLeaf<AstNodeVarRef>() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
template <>
|
|
|
|
|
constexpr bool AstNode::isLeaf<AstVarRef>() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
template <>
|
|
|
|
|
constexpr bool AstNode::isLeaf<AstVarXRef>() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-07-31 19:13:55 +02:00
|
|
|
|
|
|
|
|
// foreach implementation
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename T_Arg, typename Callable>
|
|
|
|
|
void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f, bool visitNext) {
|
|
|
|
|
// Pre-order traversal implemented directly (without recursion) for speed reasons. The very
|
|
|
|
|
// first iteration (the one that operates on the input nodep) is special, as we might or
|
|
|
|
|
// might not need to enqueue nodep->nextp() depending on VisitNext, while in all other
|
|
|
|
|
// iterations, we do want to enqueue nodep->nextp(). Duplicating code (via
|
|
|
|
|
// 'foreachImplVisit') for the initial iteration here to avoid an extra branch in the loop
|
|
|
|
|
|
|
|
|
|
using T_Arg_NonConst = typename std::remove_const<T_Arg>::type;
|
|
|
|
|
using Node = ConstCorrectAstNode<T_Arg>;
|
|
|
|
|
|
|
|
|
|
// Traversal stack
|
|
|
|
|
std::vector<Node*> stack; // Kept as a vector for easy resizing
|
|
|
|
|
Node** basep = nullptr; // Pointer to base of stack
|
|
|
|
|
Node** topp = nullptr; // Pointer to top of stack
|
|
|
|
|
Node** limp = nullptr; // Pointer to stack limit (when need growing)
|
|
|
|
|
|
|
|
|
|
// We prefetch this far into the stack
|
|
|
|
|
constexpr int prefetchDistance = 2;
|
|
|
|
|
|
|
|
|
|
// Grow stack to given size
|
|
|
|
|
const auto grow = [&](size_t size) {
|
|
|
|
|
const ptrdiff_t occupancy = topp - basep;
|
|
|
|
|
stack.resize(size);
|
|
|
|
|
basep = stack.data() + prefetchDistance;
|
|
|
|
|
topp = basep + occupancy;
|
|
|
|
|
limp = basep + size - 5; // We push max 5 items per iteration
|
|
|
|
|
};
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Initial stack size
|
|
|
|
|
grow(32);
|
|
|
|
|
|
|
|
|
|
// We want some non-null pointers at the beginning. These will be prefetched, but not
|
|
|
|
|
// visited, so the root node will suffice. This eliminates needing branches in the loop.
|
|
|
|
|
for (int i = -prefetchDistance; i; ++i) basep[i] = nodep;
|
|
|
|
|
|
|
|
|
|
// Visit given node, enqueue children for traversal
|
|
|
|
|
const auto visit = [&](Node* currp) {
|
|
|
|
|
// Type test this node
|
|
|
|
|
if (AstNode::privateTypeTest<T_Arg_NonConst>(currp)) {
|
|
|
|
|
// Call the client function
|
|
|
|
|
f(static_cast<T_Arg*>(currp));
|
|
|
|
|
// Short circuit if iterating leaf nodes
|
|
|
|
|
if VL_CONSTEXPR_CXX17 (isLeaf<T_Arg_NonConst>()) return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enqueue children for traversal, unless futile
|
|
|
|
|
if (mayBeUnder<T_Arg_NonConst>(currp)) {
|
|
|
|
|
if (AstNode* const op4p = currp->op4p()) *topp++ = op4p;
|
|
|
|
|
if (AstNode* const op3p = currp->op3p()) *topp++ = op3p;
|
|
|
|
|
if (AstNode* const op2p = currp->op2p()) *topp++ = op2p;
|
|
|
|
|
if (AstNode* const op1p = currp->op1p()) *topp++ = op1p;
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Enqueue the next of the root node, if required
|
|
|
|
|
if (visitNext && nodep->nextp()) *topp++ = nodep->nextp();
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Visit the root node
|
|
|
|
|
visit(nodep);
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Visit the rest of the tree
|
|
|
|
|
while (VL_LIKELY(topp > basep)) {
|
|
|
|
|
// Pop next node in the traversal
|
|
|
|
|
Node* const headp = *--topp;
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Prefetch in case we are ascending the tree
|
|
|
|
|
ASTNODE_PREFETCH_NON_NULL(topp[-prefetchDistance]);
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Ensure we have stack space for nextp and the 4 children
|
|
|
|
|
if (VL_UNLIKELY(topp >= limp)) grow(stack.size() * 2);
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Enqueue the next node
|
|
|
|
|
if (headp->nextp()) *topp++ = headp->nextp();
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Visit the head node
|
|
|
|
|
visit(headp);
|
2022-07-31 19:13:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// predicate implementation
|
2022-10-20 14:48:44 +02:00
|
|
|
template <typename T_Arg, bool Default, typename Callable>
|
|
|
|
|
bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p) {
|
|
|
|
|
// Implementation similar to foreach, but abort traversal as soon as result is determined
|
|
|
|
|
using T_Arg_NonConst = typename std::remove_const<T_Arg>::type;
|
|
|
|
|
using Node = ConstCorrectAstNode<T_Arg>;
|
|
|
|
|
|
|
|
|
|
// Traversal stack
|
|
|
|
|
std::vector<Node*> stack; // Kept as a vector for easy resizing
|
|
|
|
|
Node** basep = nullptr; // Pointer to base of stack
|
|
|
|
|
Node** topp = nullptr; // Pointer to top of stack
|
|
|
|
|
Node** limp = nullptr; // Pointer to stack limit (when need growing)
|
|
|
|
|
|
|
|
|
|
// We prefetch this far into the stack
|
|
|
|
|
constexpr int prefetchDistance = 2;
|
|
|
|
|
|
|
|
|
|
// Grow stack to given size
|
|
|
|
|
const auto grow = [&](size_t size) {
|
|
|
|
|
const ptrdiff_t occupancy = topp - basep;
|
|
|
|
|
stack.resize(size);
|
|
|
|
|
basep = stack.data() + prefetchDistance;
|
|
|
|
|
topp = basep + occupancy;
|
|
|
|
|
limp = basep + size - 5; // We push max 5 items per iteration
|
|
|
|
|
};
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Initial stack size
|
|
|
|
|
grow(32);
|
|
|
|
|
|
|
|
|
|
// We want some non-null pointers at the beginning. These will be prefetched, but not
|
|
|
|
|
// visited, so the root node will suffice. This eliminates needing branches in the loop.
|
|
|
|
|
for (int i = -prefetchDistance; i; ++i) basep[i] = nodep;
|
|
|
|
|
|
|
|
|
|
// Visit given node, enqueue children for traversal, return true if result determined.
|
|
|
|
|
const auto visit = [&](Node* currp) {
|
|
|
|
|
// Type test this node
|
|
|
|
|
if (AstNode::privateTypeTest<T_Arg_NonConst>(currp)) {
|
|
|
|
|
// Call the client function
|
|
|
|
|
if (p(static_cast<T_Arg*>(currp)) != Default) return true;
|
|
|
|
|
// Short circuit if iterating leaf nodes
|
|
|
|
|
if VL_CONSTEXPR_CXX17 (isLeaf<T_Arg_NonConst>()) return false;
|
|
|
|
|
}
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Enqueue children for traversal, unless futile
|
|
|
|
|
if (mayBeUnder<T_Arg_NonConst>(currp)) {
|
|
|
|
|
if (AstNode* const op4p = currp->op4p()) *topp++ = op4p;
|
|
|
|
|
if (AstNode* const op3p = currp->op3p()) *topp++ = op3p;
|
|
|
|
|
if (AstNode* const op2p = currp->op2p()) *topp++ = op2p;
|
|
|
|
|
if (AstNode* const op1p = currp->op1p()) *topp++ = op1p;
|
|
|
|
|
}
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
return false;
|
|
|
|
|
};
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Visit the root node
|
|
|
|
|
if (visit(nodep)) return !Default;
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Visit the rest of the tree
|
|
|
|
|
while (VL_LIKELY(topp > basep)) {
|
|
|
|
|
// Pop next node in the traversal
|
|
|
|
|
Node* const headp = *--topp;
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Prefetch in case we are ascending the tree
|
|
|
|
|
ASTNODE_PREFETCH_NON_NULL(topp[-prefetchDistance]);
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Ensure we have stack space for nextp and the 4 children
|
|
|
|
|
if (VL_UNLIKELY(topp >= limp)) grow(stack.size() * 2);
|
2022-07-31 19:13:55 +02:00
|
|
|
|
2022-10-20 14:48:44 +02:00
|
|
|
// Enqueue the next node
|
|
|
|
|
if (headp->nextp()) *topp++ = headp->nextp();
|
|
|
|
|
|
|
|
|
|
// Visit the head node
|
|
|
|
|
if (visit(headp)) return !Default;
|
2022-07-31 19:13:55 +02:00
|
|
|
}
|
2022-10-20 14:48:44 +02:00
|
|
|
|
|
|
|
|
return Default;
|
2022-07-31 19:13:55 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!rhs) {
|
2020-08-15 16:12:55 +02:00
|
|
|
os << "nullptr";
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
rhs->dump(os);
|
|
|
|
|
}
|
|
|
|
|
return os;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
2022-02-05 17:04:48 +01:00
|
|
|
|
|
|
|
|
// VNRef is std::reference_wrapper that can only hold AstNode subtypes
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T_Node>
|
2022-02-05 17:04:48 +01:00
|
|
|
class VNRef final : public std::reference_wrapper<T_Node> {
|
|
|
|
|
static_assert(std::is_base_of<AstNode, T_Node>::value,
|
|
|
|
|
"Type parameter 'T_Node' must be a subtype of AstNode");
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template <typename U>
|
|
|
|
|
VNRef(U&& x)
|
|
|
|
|
: std::reference_wrapper<T_Node>{x} {}
|
|
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
VNRef(const std::reference_wrapper<T_Node>& other)
|
2022-02-05 17:04:48 +01:00
|
|
|
: std::reference_wrapper<T_Node>{other} {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static_assert(sizeof(VNRef<AstNode>) == sizeof(std::reference_wrapper<AstNode>),
|
|
|
|
|
"VNRef should not contain extra members");
|
|
|
|
|
|
|
|
|
|
// Specializations of std::hash and std::equal_to for VNRef. This in turn
|
|
|
|
|
// enables us to use for example std::unordered_set<VNRef<AstNode>> for
|
|
|
|
|
// sets using equality (AstNode::sameTree) rather than identity comparisons,
|
|
|
|
|
// without having to copy nodes into the collections.
|
|
|
|
|
|
|
|
|
|
// Forward declaration to avoid including V3Hasher.h which needs V3Ast.h (this file).
|
2022-05-15 14:30:04 +02:00
|
|
|
size_t V3HasherUncachedHash(const AstNode&);
|
2022-02-05 17:04:48 +01:00
|
|
|
|
|
|
|
|
// Specialization of std::hash for VNRef
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T_Node>
|
2022-02-05 17:04:48 +01:00
|
|
|
struct std::hash<VNRef<T_Node>> final {
|
|
|
|
|
size_t operator()(VNRef<T_Node> r) const { return V3HasherUncachedHash(r); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Specialization of std::equal_to for VNRef
|
2022-08-05 11:56:57 +02:00
|
|
|
template <typename T_Node>
|
2022-02-05 17:04:48 +01:00
|
|
|
struct std::equal_to<VNRef<T_Node>> final {
|
|
|
|
|
size_t operator()(VNRef<T_Node> ra, VNRef<T_Node> rb) const {
|
|
|
|
|
return ra.get().sameTree(&(rb.get()));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2018-05-11 02:55:37 +02:00
|
|
|
//######################################################################
|
2022-01-02 19:56:40 +01:00
|
|
|
// Inline VNVisitor METHODS
|
2018-05-11 02:55:37 +02:00
|
|
|
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); }
|
|
|
|
|
void VNVisitor::iterateNull(AstNode* nodep) {
|
2021-05-21 15:34:27 +02:00
|
|
|
if (VL_LIKELY(nodep)) nodep->accept(*this);
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); }
|
|
|
|
|
void VNVisitor::iterateChildrenBackwards(AstNode* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
nodep->iterateChildrenBackwards(*this);
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); }
|
|
|
|
|
void VNVisitor::iterateAndNextNull(AstNode* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this);
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) {
|
2021-12-22 12:41:29 +01:00
|
|
|
if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this);
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
void VNVisitor::iterateAndNextConstNull(AstNode* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
|
|
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
return nodep->iterateSubtreeReturnEdits(*this);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-04 12:03:41 +02:00
|
|
|
// Include macros generated by 'astgen'. These include ASTGEN_MEMBERS_Ast<Node>
|
2022-09-15 20:43:56 +02:00
|
|
|
// for each AstNode sub-type, and ASTGEN_SUPER_<Node> for concrete final
|
|
|
|
|
// AstNode sub-types. The generated members include boilerplate methods related
|
|
|
|
|
// to cloning, visitor dispatch, and other functionality. ASTGEN_SUPER_<Node>
|
|
|
|
|
// is the necessary constructor invocation for concrete AstNode sub-types
|
|
|
|
|
// that passes the generated type-id numbers all the way back to AstNode.
|
|
|
|
|
// For precise details please read the generated macros.
|
|
|
|
|
#include "V3Ast__gen_macros.h"
|
2022-09-15 14:10:39 +02:00
|
|
|
|
|
|
|
|
// AstNode subclasses
|
|
|
|
|
#include "V3AstNodeDType.h"
|
2022-10-12 11:19:21 +02:00
|
|
|
#include "V3AstNodeExpr.h"
|
2022-09-15 14:10:39 +02:00
|
|
|
#include "V3AstNodeOther.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-15 14:10:39 +02:00
|
|
|
// Inline function definitions need to go last
|
|
|
|
|
#include "V3AstInlines.h"
|
2013-05-28 03:39:19 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
#endif // Guard
|