512 lines
20 KiB
C++
512 lines
20 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: DfgVertex sub-classes
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
// Version 2.0.
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// This is a data-flow graph based representation of combinational logic,
|
|
// the main difference from a V3Graph is that DfgVertex owns the storage
|
|
// of it's input edges (operands/sources/arguments), and can access each
|
|
// input edge directly by indexing, making modifications more efficient
|
|
// than the linked list based structures used by V3Graph.
|
|
//
|
|
// A bulk of the DfgVertex sub-types are generated by astgen, and are
|
|
// analogous to the corresponding AstNode sub-types.
|
|
//
|
|
// See also the internals documentation docs/internals.rst
|
|
//
|
|
//*************************************************************************
|
|
|
|
#ifndef VERILATOR_V3DFGVERTICES_H_
|
|
#define VERILATOR_V3DFGVERTICES_H_
|
|
|
|
#ifndef VERILATOR_V3DFG_H_
|
|
#error "Use V3Dfg.h as the include"
|
|
#include "V3Dfg.h" // This helps code analysis tools pick up symbols in V3Dfg.h
|
|
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
|
|
#endif
|
|
|
|
// Include macros generated by 'astgen'. These include DFGGEN_MEMBERS_<Node>
|
|
// for each DfgVertex sub-type. The generated members include boilerplate
|
|
// methods related to cloning, visitor dispatch, and other functionality.
|
|
// For precise details please read the generated macros.
|
|
#include "V3Dfg__gen_macros.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Variable vertices - represent a variables
|
|
|
|
class DfgVertexVar VL_NOT_FINAL : public DfgVertex {
|
|
// Represents a variable. It has 2 optional inputs, 'srcp' and 'defaultp'.
|
|
|
|
AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex)
|
|
AstVarScope* const m_varScopep; // The AstVarScope associated with this vertex (not owned)
|
|
// Location of driver of this variable. Only used for converting back to Ast. Might be nullptr.
|
|
FileLine* m_driverFileLine = nullptr;
|
|
// If this DfgVertexVar is a synthesized temporary, this is the original Var/VarScope it stands
|
|
// for. It might point to m_varp/m_varScopep itself to indicate it's a temporary without an
|
|
// associated input Var/VarScope.
|
|
AstNode* m_tmpForp = nullptr;
|
|
|
|
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, AstVarScope* vscp)
|
|
: DfgVertex{dfg, type, varp->fileline(), *DfgDataType::fromAst(varp->dtypep())}
|
|
, m_varp{varp}
|
|
, m_varScopep{vscp} {
|
|
#ifdef VL_DEBUG
|
|
if (v3Global.rootp()->topScopep()) {
|
|
UASSERT_OBJ(vscp, varp, "Un-scoped DfgVertexVar created in scoped DfgGraph");
|
|
} else {
|
|
UASSERT_OBJ(!vscp, varp, "Scoped DfgVertexVar created in un-scoped DfgGraph");
|
|
}
|
|
#endif
|
|
// Increment reference count
|
|
AstNode* const variablep = nodep();
|
|
variablep->user1(variablep->user1() + 0x10);
|
|
UASSERT_OBJ((variablep->user1() >> 4) > 0, variablep, "Reference count overflow");
|
|
// Allocate sources
|
|
newInput();
|
|
newInput();
|
|
}
|
|
|
|
protected:
|
|
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp)
|
|
: DfgVertexVar{dfg, type, varp, nullptr} {}
|
|
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
|
|
: DfgVertexVar{dfg, type, vscp->varp(), vscp} {}
|
|
|
|
public:
|
|
~DfgVertexVar() {
|
|
// Decrement reference count
|
|
AstNode* const variablep = nodep();
|
|
variablep->user1(variablep->user1() - 0x10);
|
|
UASSERT_OBJ((variablep->user1() >> 4) >= 0, variablep, "Reference count underflow");
|
|
}
|
|
ASTGEN_MEMBERS_DfgVertexVar;
|
|
|
|
// The driver of the variable. Might be nullptr if driven exernally (input to DfgGraph).
|
|
DfgVertex* srcp() const { return inputp(0); }
|
|
void srcp(DfgVertex* vtxp) { inputp(0, vtxp); }
|
|
// The default value of the variable. This defines the parts not driven by 'srcp', maybe null
|
|
DfgVertex* defaultp() const { return inputp(1); }
|
|
void defaultp(DfgVertex* vtxp) { inputp(1, vtxp); }
|
|
|
|
std::string srcName(size_t idx) const override final { return idx ? "defaultp" : "srcp"; }
|
|
|
|
// The Ast variable this vertex representess
|
|
AstVar* varp() const { return m_varp; }
|
|
AstVarScope* varScopep() const { return m_varScopep; }
|
|
AstNode* nodep() const {
|
|
return m_varScopep ? static_cast<AstNode*>(m_varScopep) : static_cast<AstNode*>(m_varp);
|
|
}
|
|
|
|
// If this is a temporary, the Ast variable it stands for, or same as
|
|
// 'nodep()' if it's a temporary with no associated original Ast variable.
|
|
AstNode* tmpForp() const { return m_tmpForp; }
|
|
void tmpForp(AstNode* nodep) { m_tmpForp = nodep; }
|
|
|
|
// Location of driver of variable (only used if 'srcp' is not a splice)
|
|
FileLine* driverFileLine() const { return m_driverFileLine; }
|
|
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
|
|
|
|
// Variable referenced from other DFG in the same module/netlist
|
|
bool hasDfgRefs() const { return nodep()->user1() >> 5; } // I.e.: (nodep()->user1() >> 4) > 1
|
|
|
|
// Variable referenced from Ast code in the same module/netlist
|
|
static bool hasModRdRefs(const AstNode* nodep) { return nodep->user1() & 0x04; }
|
|
static bool hasModWrRefs(const AstNode* nodep) { return nodep->user1() & 0x08; }
|
|
static void setHasModRdRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x04); }
|
|
static void setHasModWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x08); }
|
|
bool hasModRdRefs() const { return hasModRdRefs(nodep()); }
|
|
bool hasModWrRefs() const { return hasModWrRefs(nodep()); }
|
|
bool hasModRefs() const { return hasModRdRefs() || hasModWrRefs(); }
|
|
void setHasModRdRefs() const { setHasModRdRefs(nodep()); }
|
|
void setHasModWrRefs() const { setHasModWrRefs(nodep()); }
|
|
|
|
// Variable referenced outside the containing module/netlist.
|
|
static bool hasExtRdRefs(const AstNode* nodep) { return nodep->user1() & 0x01; }
|
|
static bool hasExtWrRefs(const AstNode* nodep) { return nodep->user1() & 0x02; }
|
|
static void setHasExtRdRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x01); }
|
|
static void setHasExtWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x02); }
|
|
bool hasExtRdRefs() const { return hasExtRdRefs(nodep()); }
|
|
bool hasExtWrRefs() const { return hasExtWrRefs(nodep()); }
|
|
bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); }
|
|
|
|
// The value of this vertex might differ from what is defined by its drivers
|
|
// 'srcp' and 'defaultp'. That is, it might be assigned, possibly partially,
|
|
// or abruptly outside the graph, hence it is not equivalent to its 'srcp'.
|
|
static bool isVolatile(const AstNode* nodep) {
|
|
return hasModWrRefs(nodep) || hasExtWrRefs(nodep);
|
|
}
|
|
bool isVolatile() const { return isVolatile(nodep()); }
|
|
};
|
|
|
|
class DfgVarArray final : public DfgVertexVar {
|
|
friend class DfgVertex;
|
|
friend class DfgVisitor;
|
|
|
|
public:
|
|
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
|
: DfgVertexVar{dfg, dfgType(), varp} {
|
|
UASSERT_OBJ(isArray(), varp, "Non-array DfgVarArray");
|
|
}
|
|
DfgVarArray(DfgGraph& dfg, AstVarScope* vscp)
|
|
: DfgVertexVar{dfg, dfgType(), vscp} {
|
|
UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray");
|
|
}
|
|
ASTGEN_MEMBERS_DfgVarArray;
|
|
};
|
|
|
|
class DfgVarPacked final : public DfgVertexVar {
|
|
friend class DfgVertex;
|
|
friend class DfgVisitor;
|
|
|
|
public:
|
|
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
|
: DfgVertexVar{dfg, dfgType(), varp} {
|
|
UASSERT_OBJ(isPacked(), varp, "Non-packed DfgVarPacked");
|
|
}
|
|
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
|
: DfgVertexVar{dfg, dfgType(), vscp} {
|
|
UASSERT_OBJ(isPacked(), vscp, "Non-packed DfgVarPacked");
|
|
}
|
|
ASTGEN_MEMBERS_DfgVarPacked;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Nullary vertices - 0 inputs
|
|
|
|
class DfgVertexNullary VL_NOT_FINAL : public DfgVertex {
|
|
protected:
|
|
DfgVertexNullary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertex{dfg, type, flp, dtype} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexNullary;
|
|
std::string srcName(size_t) const override final { V3ERROR_NA_RETURN(""); }
|
|
};
|
|
|
|
class DfgConst final : public DfgVertexNullary {
|
|
friend class DfgVertex;
|
|
friend class DfgVisitor;
|
|
|
|
V3Number m_num; // Constant value
|
|
|
|
public:
|
|
DfgConst(DfgGraph& dfg, FileLine* flp, const V3Number& num)
|
|
: DfgVertexNullary{dfg, dfgType(), flp, DfgDataType::packed(num.width())}
|
|
, m_num{num} {}
|
|
DfgConst(DfgGraph& dfg, FileLine* flp, size_t width, uint32_t value)
|
|
: DfgVertexNullary{dfg, dfgType(), flp, DfgDataType::packed(width)}
|
|
, m_num{flp, static_cast<int>(width), value} {}
|
|
|
|
ASTGEN_MEMBERS_DfgConst;
|
|
|
|
V3Number& num() { return m_num; }
|
|
const V3Number& num() const { return m_num; }
|
|
|
|
size_t toSizeT() const { return static_cast<size_t>(num().toUQuad()); }
|
|
uint32_t toU32() const { return num().toUInt(); }
|
|
|
|
bool isZero() const { return num().isEqZero(); }
|
|
bool isOnes() const { return num().isEqAllOnes(width()); }
|
|
|
|
// Does this DfgConst have the given value? Note this is not easy to answer if wider than 32.
|
|
bool hasValue(uint32_t value) const {
|
|
return !num().isFourState() && num().edataWord(0) == value && num().mostSetBitP1() <= 32;
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Unary vertices - 1 inputs
|
|
|
|
class DfgVertexUnary VL_NOT_FINAL : public DfgVertex {
|
|
protected:
|
|
DfgVertexUnary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertex{dfg, type, flp, dtype} {
|
|
newInput();
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexUnary;
|
|
DfgVertex* srcp() const { return inputp(0); }
|
|
void srcp(DfgVertex* vtxp) { inputp(0, vtxp); }
|
|
std::string srcName(size_t) const override final { return ""; }
|
|
};
|
|
|
|
class DfgSel final : public DfgVertexUnary {
|
|
// AstSel is binary, but 'lsbp' is very often constant. As AstSel is fairly
|
|
// common, we special case as a DfgSel for the constant 'lsbp', and as
|
|
// 'DfgMux` for the non-constant 'lsbp'.
|
|
uint32_t m_lsb = 0; // The LSB index
|
|
|
|
public:
|
|
DfgSel(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexUnary{dfg, dfgType(), flp, dtype} {}
|
|
ASTGEN_MEMBERS_DfgSel;
|
|
|
|
DfgVertex* fromp() const { return srcp(); }
|
|
void fromp(DfgVertex* vtxp) { srcp(vtxp); }
|
|
uint32_t lsb() const { return m_lsb; }
|
|
void lsb(uint32_t value) { m_lsb = value; }
|
|
};
|
|
|
|
class DfgUnitArray final : public DfgVertexUnary {
|
|
// This is a type adapter for modeling arrays. It's a single element array,
|
|
// with the value of the single element being the source operand.
|
|
public:
|
|
DfgUnitArray(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexUnary{dfg, dfgType(), flp, dtype} {
|
|
UASSERT_OBJ(isArray(), flp, "Non-array DfgUnitArray");
|
|
UASSERT_OBJ(size() == 1, flp, "DfgUnitArray must have a single element");
|
|
}
|
|
ASTGEN_MEMBERS_DfgUnitArray;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Binary vertices - 2 inputs
|
|
|
|
class DfgVertexBinary VL_NOT_FINAL : public DfgVertex {
|
|
protected:
|
|
DfgVertexBinary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertex{dfg, type, flp, dtype} {
|
|
newInput();
|
|
newInput();
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexBinary;
|
|
};
|
|
|
|
class DfgMux final : public DfgVertexBinary {
|
|
// AstSel is binary, but 'lsbp' is very often constant. As AstSel is fairly
|
|
// common, we special case as a DfgSel for the constant 'lsbp', and as
|
|
// 'DfgMux` for the non-constant 'lsbp'.
|
|
public:
|
|
DfgMux(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexBinary{dfg, dfgType(), flp, dtype} {}
|
|
ASTGEN_MEMBERS_DfgMux;
|
|
|
|
DfgVertex* fromp() const { return inputp(0); }
|
|
void fromp(DfgVertex* vtxp) { inputp(0, vtxp); }
|
|
DfgVertex* lsbp() const { return inputp(1); }
|
|
void lsbp(DfgVertex* vtxp) { inputp(1, vtxp); }
|
|
|
|
std::string srcName(size_t idx) const override { return idx ? "lsbp" : "fromp"; }
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Ternary vertices - 3 inputs
|
|
|
|
class DfgVertexTernary VL_NOT_FINAL : public DfgVertex {
|
|
protected:
|
|
DfgVertexTernary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertex{dfg, type, flp, dtype} {
|
|
newInput();
|
|
newInput();
|
|
newInput();
|
|
}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexTernary;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Variadic vertices - variable number of inputs
|
|
|
|
class DfgVertexVariadic VL_NOT_FINAL : public DfgVertex {
|
|
protected:
|
|
DfgVertexVariadic(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertex{dfg, type, flp, dtype} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexVariadic;
|
|
};
|
|
|
|
class DfgVertexSplice VL_NOT_FINAL : public DfgVertexVariadic {
|
|
// Represents a partial update to a varibale
|
|
|
|
struct DriverData final {
|
|
uint32_t m_lo; // Low index of range driven by this driver
|
|
FileLine* m_flp; // Location of this driver
|
|
DriverData() = delete;
|
|
DriverData(uint32_t lo, FileLine* flp)
|
|
: m_lo{lo}
|
|
, m_flp{flp} {}
|
|
};
|
|
std::vector<DriverData> m_driverData; // Additional data associated with each driver
|
|
|
|
protected:
|
|
DfgVertexSplice(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexVariadic{dfg, type, flp, dtype} {}
|
|
|
|
public:
|
|
ASTGEN_MEMBERS_DfgVertexSplice;
|
|
|
|
// Add driver
|
|
void addDriver(DfgVertex* vtxp, uint32_t lo, FileLine* flp) {
|
|
UASSERT_OBJ(!vtxp->is<DfgLogic>(), vtxp, "addDriver called with DfgLogic");
|
|
m_driverData.emplace_back(lo, flp);
|
|
newInput()->relinkSrcp(vtxp);
|
|
}
|
|
|
|
void resetDrivers() {
|
|
resetInputs();
|
|
m_driverData.clear();
|
|
}
|
|
|
|
std::string srcName(size_t idx) const override final {
|
|
const uint32_t lo = m_driverData[idx].m_lo;
|
|
const uint32_t hi = lo + inputp(idx)->size() - 1;
|
|
return '[' + std::to_string(hi) + ':' + std::to_string(lo) + ']';
|
|
}
|
|
|
|
FileLine* driverFileLine(size_t idx) const { return m_driverData.at(idx).m_flp; }
|
|
|
|
DfgVertex* driverAt(size_t idx) const {
|
|
const size_t n = nInputs();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (m_driverData[i].m_lo == idx) return inputp(i);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// If drives the whole result explicitly (not through defaultp), this is
|
|
// the actual driver this DfgVertexSplice can be replaced with.
|
|
DfgVertex* wholep() {
|
|
if (nInputs() != 1) return nullptr;
|
|
if (m_driverData[0].m_lo != 0) return nullptr;
|
|
DfgVertex* const vtxp = inputp(0);
|
|
if (vtxp->size() != size()) return nullptr;
|
|
if (const DfgUnitArray* const uap = vtxp->cast<DfgUnitArray>()) {
|
|
if (DfgVertexSplice* const splicep = uap->srcp()->cast<DfgVertexSplice>()) {
|
|
if (!splicep->wholep()) return nullptr;
|
|
}
|
|
}
|
|
return vtxp;
|
|
}
|
|
|
|
bool foreachDriver(std::function<bool(DfgVertex&, uint32_t, FileLine*)> f) {
|
|
const size_t n = nInputs();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (f(*inputp(i), m_driverData[i].m_lo, m_driverData[i].m_flp)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool foreachDriver(std::function<bool(const DfgVertex&, uint32_t, FileLine*)> f) const {
|
|
const size_t n = nInputs();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (f(*inputp(i), m_driverData[i].m_lo, m_driverData[i].m_flp)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool foreachDriver(std::function<bool(DfgVertex&, uint32_t)> f) {
|
|
const size_t n = nInputs();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (f(*inputp(i), m_driverData[i].m_lo)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool foreachDriver(std::function<bool(const DfgVertex&, uint32_t)> f) const {
|
|
const size_t n = nInputs();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
if (f(*inputp(i), m_driverData[i].m_lo)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class DfgSpliceArray final : public DfgVertexSplice {
|
|
friend class DfgVertex;
|
|
friend class DfgVisitor;
|
|
|
|
public:
|
|
DfgSpliceArray(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexSplice{dfg, dfgType(), flp, dtype} {
|
|
UASSERT_OBJ(isArray(), flp, "Non-array DfgSpliceArray");
|
|
}
|
|
ASTGEN_MEMBERS_DfgSpliceArray;
|
|
};
|
|
|
|
class DfgSplicePacked final : public DfgVertexSplice {
|
|
friend class DfgVertex;
|
|
friend class DfgVisitor;
|
|
|
|
public:
|
|
DfgSplicePacked(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
|
: DfgVertexSplice{dfg, dfgType(), flp, dtype} {
|
|
UASSERT_OBJ(isPacked(), flp, "Non-packed DfgSplicePacked");
|
|
}
|
|
ASTGEN_MEMBERS_DfgSplicePacked;
|
|
};
|
|
|
|
class DfgLogic final : public DfgVertexVariadic {
|
|
// Generic vertex representing a whole combinational process
|
|
AstAlways* const m_nodep; // The Ast logic represented by this vertex
|
|
AstScope* const m_scopep; // The AstScope m_nodep is under, iff scoped
|
|
const std::unique_ptr<CfgGraph> m_cfgp;
|
|
std::vector<DfgVertex*> m_synth; // Vertices this logic was synthesized into
|
|
bool m_selectedForSynthesis = false; // Logic selected for synthesis
|
|
bool m_nonSynthesizable = false; // Logic is not synthesizeable (by DfgSynthesis)
|
|
bool m_reverted = false; // Logic was synthesized (in part if non synthesizable) then reverted
|
|
|
|
public:
|
|
DfgLogic(DfgGraph& dfg, AstAlways* nodep, AstScope* scopep, std::unique_ptr<CfgGraph> cfgp)
|
|
: DfgVertexVariadic{dfg, dfgType(), nodep->fileline(), DfgDataType::null()}
|
|
, m_nodep{nodep}
|
|
, m_scopep{scopep}
|
|
, m_cfgp{std::move(cfgp)} {}
|
|
|
|
ASTGEN_MEMBERS_DfgLogic;
|
|
|
|
std::string srcName(size_t) const override final { return ""; }
|
|
|
|
// Can only be driven by DfgVertexVar
|
|
void addInput(DfgVertexVar* varp) { newInput()->relinkSrcp(varp); }
|
|
|
|
// Accessors
|
|
AstAlways* nodep() const { return m_nodep; }
|
|
AstScope* scopep() const { return m_scopep; }
|
|
CfgGraph& cfg() { return *m_cfgp; }
|
|
const CfgGraph& cfg() const { return *m_cfgp; }
|
|
std::vector<DfgVertex*>& synth() { return m_synth; }
|
|
const std::vector<DfgVertex*>& synth() const { return m_synth; }
|
|
bool selectedForSynthesis() const { return m_selectedForSynthesis; }
|
|
void setSelectedForSynthesis() { m_selectedForSynthesis = true; }
|
|
bool nonSynthesizable() const { return m_nonSynthesizable; }
|
|
void setNonSynthesizable() { m_nonSynthesizable = true; }
|
|
bool reverted() const { return m_reverted; }
|
|
void setReverted() { m_reverted = true; }
|
|
};
|
|
|
|
class DfgUnresolved final : public DfgVertexVariadic {
|
|
// Represents a collection of unresolved variable drivers before synthesis
|
|
public:
|
|
DfgUnresolved(DfgGraph& dfg, const DfgVertexVar* vtxp)
|
|
: DfgVertexVariadic{dfg, dfgType(), vtxp->fileline(), vtxp->dtype()} {}
|
|
ASTGEN_MEMBERS_DfgUnresolved;
|
|
|
|
std::string srcName(size_t) const override final { return ""; }
|
|
|
|
// Can only be driven by DfgLogic or DfgVertexSplice
|
|
void addDriver(DfgLogic* vtxp) { newInput()->relinkSrcp(vtxp); }
|
|
void addDriver(DfgVertexSplice* vtxp) { newInput()->relinkSrcp(vtxp); }
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// The rest of the vertex types are generated by 'astgen' from AstNodeExpr
|
|
#include "V3Dfg__gen_auto_classes.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Inline method definitions
|
|
|
|
#endif
|