Document and ensure OrderGraph is bipartite

Minor refactoring and documentation. No functional change.
This commit is contained in:
Geza Lore 2022-08-24 17:17:57 +01:00
parent 2ecda74471
commit 8de21e9bb7
5 changed files with 265 additions and 226 deletions

View File

@ -86,6 +86,7 @@
#include "V3GraphStream.h"
#include "V3List.h"
#include "V3OrderGraph.h"
#include "V3OrderMoveGraph.h"
#include "V3Partition.h"
#include "V3PartitionGraph.h"
#include "V3Sched.h"
@ -102,21 +103,6 @@
#include <unordered_map>
#include <vector>
//######################################################################
// Functions for above graph classes
void OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) {
if (debug()) cout << "-Info-Loop: " << vertexp << "\n";
if (OrderLogicVertex* const vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
std::cerr << vvertexp->nodep()->fileline()->warnOther()
<< " Example path: " << vvertexp->nodep()->typeName() << endl;
}
if (OrderVarVertex* const vvertexp = dynamic_cast<OrderVarVertex*>(vertexp)) {
std::cerr << vvertexp->vscp()->fileline()->warnOther()
<< " Example path: " << vvertexp->vscp()->prettyName() << endl;
}
}
//######################################################################
// Order information stored under each AstNode::user1p()...
@ -138,7 +124,7 @@ private:
public:
// METHODS
OrderVarVertex* getVarVertex(V3Graph* graphp, AstVarScope* varscp, VarVertexType type) {
OrderVarVertex* getVarVertex(OrderGraph* graphp, AstVarScope* varscp, VarVertexType type) {
const unsigned idx = static_cast<unsigned>(type);
OrderVarVertex* vertexp = m_vertexps[idx];
if (!vertexp) {
@ -312,21 +298,7 @@ class OrderBuildVisitor final : public VNVisitor {
}
}
// Roles of vertices:
// VarVertexType::STD: Data dependencies for combinational logic and delayed
// assignment updates (AssignPost).
// VarVertexType::POST: Ensures all sequential blocks reading a signal do so before
// any combinational or delayed assignments update that signal.
// VarVertexType::PORD: Ensures a _d = _q AssignPre is the first write of a _d,
// before any sequential blocks write to that _d.
// VarVertexType::PRE: This is an optimization. Try to ensure that a _d = _q
// AssignPre is the last read of a _q, after all reads of that
// _q by sequential logic. Note: The model is still correct if we
// cannot satisfy this due to other constraints. If this ordering
// is possible, then combined with the PORD constraint we get
// that all writes to _d are after all reads of a _q, which then
// allows us to eliminate the _d completely and assign to the _q
// directly (this is what V3LifePost does).
// Note: See V3OrderGraph.h about the roles of the various vertex types
// Variable is produced
if (gen) {
@ -338,9 +310,9 @@ class OrderBuildVisitor final : public VNVisitor {
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
// Add edge from producing LogicVertex -> produced VarStdVertex
if (m_inPost) {
new OrderPostCutEdge(m_graphp, m_logicVxp, varVxp);
m_graphp->addSoftEdge(m_logicVxp, varVxp, WEIGHT_COMBO);
} else {
new OrderEdge(m_graphp, m_logicVxp, varVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
}
// Add edge from produced VarPostVertex -> to producing LogicVertex
@ -352,22 +324,22 @@ class OrderBuildVisitor final : public VNVisitor {
// ALWAYS do it:
// There maybe a wire a=b; between the two blocks
OrderVarVertex* const postVxp = getVarVertex(varscp, VarVertexType::POST);
new OrderEdge(m_graphp, postVxp, m_logicVxp, WEIGHT_POST);
m_graphp->addHardEdge(postVxp, m_logicVxp, WEIGHT_POST);
} else if (m_inPre) { // AstAssignPre
// Add edge from producing LogicVertex -> produced VarPordVertex
OrderVarVertex* const ordVxp = getVarVertex(varscp, VarVertexType::PORD);
new OrderEdge(m_graphp, m_logicVxp, ordVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(m_logicVxp, ordVxp, WEIGHT_NORMAL);
// Add edge from producing LogicVertex -> produced VarStdVertex
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
new OrderEdge(m_graphp, m_logicVxp, varVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
} else {
// Sequential (clocked) logic
// Add edge from produced VarPordVertex -> to producing LogicVertex
OrderVarVertex* const ordVxp = getVarVertex(varscp, VarVertexType::PORD);
new OrderEdge(m_graphp, ordVxp, m_logicVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(ordVxp, m_logicVxp, WEIGHT_NORMAL);
// Add edge from producing LogicVertex-> to produced VarStdVertex
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
new OrderEdge(m_graphp, m_logicVxp, varVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(m_logicVxp, varVxp, WEIGHT_NORMAL);
}
}
@ -382,7 +354,7 @@ class OrderBuildVisitor final : public VNVisitor {
// Ignore explicit sensitivities
OrderVarVertex* const varVxp = getVarVertex(varscp, VarVertexType::STD);
// Add edge from consumed VarStdVertex -> to consuming LogicVertex
new OrderEdge(m_graphp, varVxp, m_logicVxp, WEIGHT_MEDIUM);
m_graphp->addHardEdge(varVxp, m_logicVxp, WEIGHT_MEDIUM);
}
} else if (m_inPre) {
// AstAssignPre logic
@ -390,17 +362,17 @@ class OrderBuildVisitor final : public VNVisitor {
// This one is cutable (vs the producer) as there's only one such consumer,
// but may be many producers
OrderVarVertex* const preVxp = getVarVertex(varscp, VarVertexType::PRE);
new OrderPreCutEdge(m_graphp, preVxp, m_logicVxp);
m_graphp->addSoftEdge(preVxp, m_logicVxp, WEIGHT_PRE);
} else {
// Sequential (clocked) logic
// Add edge from consuming LogicVertex -> to consumed VarPreVertex
// Generation of 'pre' because we want to indicate it should be before
// AstAssignPre
OrderVarVertex* const preVxp = getVarVertex(varscp, VarVertexType::PRE);
new OrderEdge(m_graphp, m_logicVxp, preVxp, WEIGHT_NORMAL);
m_graphp->addHardEdge(m_logicVxp, preVxp, WEIGHT_NORMAL);
// Add edge from consuming LogicVertex -> to consumed VarPostVertex
OrderVarVertex* const postVxp = getVarVertex(varscp, VarVertexType::POST);
new OrderEdge(m_graphp, m_logicVxp, postVxp, WEIGHT_POST);
m_graphp->addHardEdge(m_logicVxp, postVxp, WEIGHT_POST);
}
}
}
@ -742,7 +714,7 @@ private:
// Path from vertexp to a logic vertex; new edge.
// Note we use the last edge's weight, not some function of
// multiple edges
new OrderEdge(m_outGraphp, moveVxp, m_logic2move[toLVertexp], weight);
new V3GraphEdge(m_outGraphp, moveVxp, m_logic2move[toLVertexp], weight);
madeDeps = true;
} else {
// This is an OrderVarVertex.
@ -767,7 +739,7 @@ private:
// Create incoming edge, from previous logic that writes
// this var, to the Vertex representing the (var,domain)
new OrderEdge(m_outGraphp, moveVxp, m_var2move[key], weight);
new V3GraphEdge(m_outGraphp, moveVxp, m_var2move[key], weight);
madeDeps = true;
}
}

View File

@ -1,6 +1,6 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Block code ordering
// DESCRIPTION: Verilator: Ordering constraint graph
//
// Code available from: https://verilator.org
//
@ -13,23 +13,52 @@
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
// OrderGraph Class Hierarchy:
//
// V3GraphVertex
// OrderMoveVertex
// MTaskMoveVertex
// OrderEitherVertex
// OrderLogicVertex
// OrderVarVertex
// OrderVarStdVertex
// OrderVarPreVertex
// OrderVarPostVertex
// OrderVarPordVertex
// OrderGraph is a bipartite graph, with the two parts being formed of only OrderLogicVertex and
// OrderVarVertex vertices respectively (i.e.: edges are always between OrderLogicVertex and
// OrderVarVertex, and never between two OrderLogicVertex or OrderVarVertex). The graph represents
// both fine-grained dependencies, and additional ordering constraints between logic blocks and
// variables. The fact that OrderGraph is bipartite is important and we take advantage of this fact
// in various algorithms, so this property must be maintained.
//
// Both OrderLogicVertex and OrderVarVertex derives from OrderEitherVertex, so OrderGraph is
// composed only of OrderEitherVertex vertices.
//
// OrderLogicVertex holds a 'logic block', which is just some computational construct that is
// ordered as a single unit. Ordering of these logic blocks is determined by the variables they
// read and write, which is represented by the edges between OrderLogicVertex and OrderVarVertex
// instances (and hence the graph is bipartite).
//
// OrderVarVertex is abstract, and has various concrete subtypes that represent various ordering
// constraints imposed by variables accessed by logic blocks. The concrete subtypes and their
// roles are:
//
// OrderVarStdVertex: Data dependencies for combinational logic and delayed assignment
// updates (AssignPost).
// OrderVarPostVertex: Ensures all sequential logic blocks reading a signal do so before any
// combinational or delayed assignments update that signal.
// OrderVarPordVertex: Ensures a _d = _q AssignPre used to implement delayed (non-blocking)
// assignments is the first write of a _d, before any sequential blocks
// write to that _d.
// OrderVarPreVertex: This is an optimization. Try to ensure that a _d = _q AssignPre is the
// last read of a _q, after all reads of that _q by sequential logic. The
// model is still correct if we cannot satisfy this due to other interfering
// constraints. If respecting this constraint is possible, then combined
// with the OrderVarPordVertex constraint we get that all writes to _d are
// after all reads of a _q, which then allows us to eliminate the _d
// completely and assign to the _q directly. This means these delayed
// assignments can be implemented without temporary storage (the redundant
// storage is eliminated in V3LifePost).
//
// Ordering constraints are represented by directed edges, where the source of an edge needs to be
// ordered before the sink of an edge. A constraint can be either hard (must be satisfied),
// represented by a non cutable edge, or a constraint can be soft (ideally should be satisfied, but
// is ok not to if other hard constraints interfere), represented by a cutable edge. Edges
// otherwise carry no additional information. TODO: what about weight?
//
// Note: It is required for hard (non-cutable) constraints to form a DAG, but together with the
// soft constraints the graph can be arbitrary so long as it remains bipartite.
//
// V3GraphEdge
// OrderEdge
// OrderPostCutEdge
// OrderPreCutEdge
//*************************************************************************
#ifndef VERILATOR_V3ORDERGRAPH_H_
@ -41,13 +70,10 @@
#include "V3Ast.h"
#include "V3Graph.h"
#include <unordered_map>
class OrderLogicVertex;
class OrderVarVertex;
class OrderMoveVertex;
class OrderMoveVertexMaker;
class OrderMoveDomScope;
//######################################################################
//======================================================================
enum OrderWeights : uint8_t {
WEIGHT_COMBO = 1, // Breakable combo logic
@ -57,26 +83,37 @@ enum OrderWeights : uint8_t {
WEIGHT_NORMAL = 32 // High weight just so dot graph looks nice
};
//######################################################################
// Graph types
//======================================================================
// Graph type
class OrderGraph final : public V3Graph {
public:
OrderGraph() = default;
virtual ~OrderGraph() override = default;
// METHODS
virtual void loopsVertexCb(V3GraphVertex* vertexp) override;
// Methods to add edges representing constraints, utilizing the type system to help us ensure
// the graph remains bipartite.
inline void addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight);
inline void addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight);
inline void addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight);
inline void addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight);
};
//######################################################################
//======================================================================
// Vertex types
class OrderEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstSenTree* m_domainp; // Clock domain (nullptr = to be computed as we iterate)
// Event domain of vertex. For OrderLogicVertex this represents the conditions when the logic
// block must be executed. For OrderVarVertex, this is the union of the domains of all the
// OrderLogicVertex vertices that drive the variable. If initially set to nullptr (e.g.: all
// OrderVarVertex and those OrderLogicVertices that represent combinational logic), then the
// ordering algorithm will compute the domain automatically based on the edges representing
// data-flow (those between OrderLogicVertex and OrderVarStdVertex), otherwise the domain is
// as given (e.g.: for those OrderLogicVertices that represent clocked logic).
AstSenTree* m_domainp;
protected:
// CONSTRUCTOR
OrderEitherVertex(V3Graph* graphp, AstSenTree* domainp)
OrderEitherVertex(OrderGraph* graphp, AstSenTree* domainp)
: V3GraphVertex{graphp}
, m_domainp{domainp} {}
virtual ~OrderEitherVertex() override = default;
@ -87,18 +124,23 @@ public:
// ACCESSORS
AstSenTree* domainp() const { return m_domainp; }
void domainp(AstSenTree* domainp) { m_domainp = domainp; }
void domainp(AstSenTree* domainp) {
#if VL_DEBUG
UASSERT(!m_domainp, "Domain should only be set once");
#endif
m_domainp = domainp;
}
};
class OrderLogicVertex final : public OrderEitherVertex {
AstNode* const m_nodep; // The logic this vertex represents
AstScope* const m_scopep; // Scope the logic is under
AstSenTree* const m_hybridp;
AstSenTree* const m_hybridp; // Additional sensitivities for hybrid combinational logic
public:
// CONSTRUCTOR
OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstSenTree* hybridp,
AstNode* nodep)
OrderLogicVertex(OrderGraph* graphp, AstScope* scopep, AstSenTree* domainp,
AstSenTree* hybridp, AstNode* nodep)
: OrderEitherVertex{graphp, domainp}
, m_nodep{nodep}
, m_scopep{scopep}
@ -131,7 +173,7 @@ class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex {
public:
// CONSTRUCTOR
OrderVarVertex(V3Graph* graphp, AstVarScope* vscp)
OrderVarVertex(OrderGraph* graphp, AstVarScope* vscp)
: OrderEitherVertex{graphp, nullptr}
, m_vscp{vscp} {}
virtual ~OrderVarVertex() override = default;
@ -151,8 +193,8 @@ public:
class OrderVarStdVertex final : public OrderVarVertex {
public:
// CONSTRUCTOR
OrderVarStdVertex(V3Graph* graphp, AstVarScope* varScp)
: OrderVarVertex{graphp, varScp} {}
OrderVarStdVertex(OrderGraph* graphp, AstVarScope* vscp)
: OrderVarVertex{graphp, vscp} {}
virtual ~OrderVarStdVertex() override = default;
// METHODS
@ -167,8 +209,8 @@ public:
class OrderVarPreVertex final : public OrderVarVertex {
public:
// CONSTRUCTOR
OrderVarPreVertex(V3Graph* graphp, AstVarScope* varScp)
: OrderVarVertex{graphp, varScp} {}
OrderVarPreVertex(OrderGraph* graphp, AstVarScope* vscp)
: OrderVarVertex{graphp, vscp} {}
virtual ~OrderVarPreVertex() override = default;
// METHODS
@ -183,8 +225,8 @@ public:
class OrderVarPostVertex final : public OrderVarVertex {
public:
// CONSTRUCTOR
OrderVarPostVertex(V3Graph* graphp, AstVarScope* varScp)
: OrderVarVertex{graphp, varScp} {}
OrderVarPostVertex(OrderGraph* graphp, AstVarScope* vscp)
: OrderVarVertex{graphp, vscp} {}
virtual ~OrderVarPostVertex() override = default;
// METHODS
@ -199,8 +241,8 @@ public:
class OrderVarPordVertex final : public OrderVarVertex {
public:
// CONSTRUCTOR
OrderVarPordVertex(V3Graph* graphp, AstVarScope* varScp)
: OrderVarVertex{graphp, varScp} {}
OrderVarPordVertex(OrderGraph* graphp, AstVarScope* vscp)
: OrderVarVertex{graphp, vscp} {}
virtual ~OrderVarPordVertex() override = default;
// METHODS
@ -212,153 +254,36 @@ public:
// LCOV_EXCL_STOP
};
//######################################################################
// Edge types
//======================================================================
// Edge type
class OrderEdge VL_NOT_FINAL : public V3GraphEdge {
public:
class OrderEdge final : public V3GraphEdge {
friend class OrderGraph; // Only the OrderGraph can create these
// CONSTRUCTOR
OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable = false)
OrderEdge(OrderGraph* graphp, OrderEitherVertex* fromp, OrderEitherVertex* top, int weight,
bool cutable)
: V3GraphEdge{graphp, fromp, top, weight, cutable} {}
virtual ~OrderEdge() override = default;
};
class OrderPostCutEdge final : public OrderEdge {
// Edge created from output of post assignment
public:
// CONSTRUCTOR
OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge{graphp, fromp, top, WEIGHT_COMBO, CUTABLE} {}
virtual ~OrderPostCutEdge() override = default;
// LCOV_EXCL_START // Debug code
virtual string dotColor() const override { return "palegreen"; }
virtual string dotColor() const override { return cutable() ? "green" : "red"; }
// LCOV_EXCL_STOP
};
class OrderPreCutEdge final : public OrderEdge {
// Edge created from var_PREVAR->consuming logic vertex
// Always breakable, just results in performance loss
// in which case we can't optimize away the pre/post delayed assignments
public:
// CONSTRUCTOR
OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge{graphp, fromp, top, WEIGHT_PRE, CUTABLE} {}
virtual ~OrderPreCutEdge() override = default;
//======================================================================
// Inline methods
// LCOV_EXCL_START // Debug code
virtual string dotColor() const override { return "khaki"; }
// LCOV_EXCL_STOP
};
//######################################################################
//--- Following only under the move graph, not the main graph
class OrderMoveVertex final : public V3GraphVertex {
enum OrderMState : uint8_t { POM_WAIT, POM_READY, POM_MOVED };
OrderLogicVertex* const m_logicp;
OrderMState m_state; // Movement state
OrderMoveDomScope* m_domScopep; // Domain/scope list information
protected:
friend class OrderProcess;
friend class OrderMoveVertexMaker;
// These only contain the "next" item,
// for the head of the list, see the same var name under OrderProcess
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
V3ListEnt<OrderMoveVertex*> m_readyVerticesE; // List of ready under domain/scope
public:
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
: V3GraphVertex{graphp}
, m_logicp{logicp}
, m_state{POM_WAIT}
, m_domScopep{nullptr} {}
virtual ~OrderMoveVertex() override = default;
// METHODS
virtual string dotColor() const override {
if (logicp()) {
return logicp()->dotColor();
} else {
return "";
}
}
virtual string name() const override {
string nm;
if (VL_UNCOVERABLE(!logicp())) { // Avoid crash when debugging
nm = "nul"; // LCOV_EXCL_LINE
} else {
nm = logicp()->name();
nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp())
+ " s=" + cvtToHex(logicp()->scopep()));
}
return nm;
}
OrderLogicVertex* logicp() const { return m_logicp; }
bool isWait() const { return m_state == POM_WAIT; }
void setReady() {
UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state");
m_state = POM_READY;
}
void setMoved() {
UASSERT(m_state == POM_READY, "Ready->Moved on node not in proper state");
m_state = POM_MOVED;
}
OrderMoveDomScope* domScopep() const { return m_domScopep; }
OrderMoveVertex* pomWaitingNextp() const { return m_pomWaitingE.nextp(); }
void domScopep(OrderMoveDomScope* ds) { m_domScopep = ds; }
};
// Similar to OrderMoveVertex, but modified for threaded code generation.
class MTaskMoveVertex final : public V3GraphVertex {
// This could be more compact, since we know m_varp and m_logicp
// cannot both be set. Each MTaskMoveVertex represents a logic node
// or a var node, it can't be both.
OrderLogicVertex* const m_logicp; // Logic represented by this vertex
const OrderEitherVertex* const m_varp; // Var represented by this vertex
const AstSenTree* const m_domainp;
public:
MTaskMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp, const OrderEitherVertex* varp,
const AstSenTree* domainp)
: V3GraphVertex{graphp}
, m_logicp{logicp}
, m_varp{varp}
, m_domainp{domainp} {
UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n");
}
virtual ~MTaskMoveVertex() override = default;
// ACCESSORS
OrderLogicVertex* logicp() const { return m_logicp; }
const OrderEitherVertex* varp() const { return m_varp; }
const AstScope* scopep() const { return m_logicp ? m_logicp->scopep() : nullptr; }
const AstSenTree* domainp() const { return m_domainp; }
virtual string dotColor() const override {
if (logicp()) {
return logicp()->dotColor();
} else {
return "yellow";
}
}
virtual string name() const override {
string nm;
if (logicp()) {
nm = logicp()->name();
nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + " s="
+ cvtToHex(logicp()->scopep())
// "color()" represents the mtask ID.
+ "\\nt=" + cvtToStr(color()));
} else {
nm = "nolog\\nt=" + cvtToStr(color());
}
return nm;
}
};
void OrderGraph::addHardEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight) {
new OrderEdge{this, fromp, top, weight, /* cutable: */ false};
}
void OrderGraph::addHardEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight) {
new OrderEdge{this, fromp, top, weight, /* cutable: */ false};
}
void OrderGraph::addSoftEdge(OrderLogicVertex* fromp, OrderVarVertex* top, int weight) {
new OrderEdge{this, fromp, top, weight, /* cutable: */ true};
}
void OrderGraph::addSoftEdge(OrderVarVertex* fromp, OrderLogicVertex* top, int weight) {
new OrderEdge{this, fromp, top, weight, /* cutable: */ true};
}
#endif // Guard

141
src/V3OrderMoveGraph.h Normal file
View File

@ -0,0 +1,141 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Ordering graph
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2022 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
//
//*************************************************************************
//
// TODO: Fix comment
//
//*************************************************************************
#ifndef VERILATOR_V3ORDERMOVEGRAPH_H_
#define VERILATOR_V3ORDERMOVEGRAPH_H_
#include "config_build.h"
#include "verilatedos.h"
#include "V3Ast.h"
#include "V3Graph.h"
#include "V3OrderGraph.h"
#include <unordered_map>
class OrderMoveDomScope;
class OrderMoveVertex final : public V3GraphVertex {
enum OrderMState : uint8_t { POM_WAIT, POM_READY, POM_MOVED };
OrderLogicVertex* const m_logicp;
OrderMState m_state; // Movement state
OrderMoveDomScope* m_domScopep; // Domain/scope list information
protected:
friend class OrderProcess;
friend class OrderMoveVertexMaker;
// These only contain the "next" item,
// for the head of the list, see the same var name under OrderProcess
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
V3ListEnt<OrderMoveVertex*> m_readyVerticesE; // List of ready under domain/scope
public:
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
: V3GraphVertex{graphp}
, m_logicp{logicp}
, m_state{POM_WAIT}
, m_domScopep{nullptr} {}
virtual ~OrderMoveVertex() override = default;
// METHODS
virtual string dotColor() const override {
if (logicp()) {
return logicp()->dotColor();
} else {
return "";
}
}
virtual string name() const override {
string nm;
if (VL_UNCOVERABLE(!logicp())) { // Avoid crash when debugging
nm = "nul"; // LCOV_EXCL_LINE
} else {
nm = logicp()->name();
nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp())
+ " s=" + cvtToHex(logicp()->scopep()));
}
return nm;
}
OrderLogicVertex* logicp() const { return m_logicp; }
bool isWait() const { return m_state == POM_WAIT; }
void setReady() {
UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state");
m_state = POM_READY;
}
void setMoved() {
UASSERT(m_state == POM_READY, "Ready->Moved on node not in proper state");
m_state = POM_MOVED;
}
OrderMoveDomScope* domScopep() const { return m_domScopep; }
OrderMoveVertex* pomWaitingNextp() const { return m_pomWaitingE.nextp(); }
void domScopep(OrderMoveDomScope* ds) { m_domScopep = ds; }
};
// Similar to OrderMoveVertex, but modified for threaded code generation.
class MTaskMoveVertex final : public V3GraphVertex {
// This could be more compact, since we know m_varp and m_logicp
// cannot both be set. Each MTaskMoveVertex represents a logic node
// or a var node, it can't be both.
OrderLogicVertex* const m_logicp; // Logic represented by this vertex
const OrderEitherVertex* const m_varp; // Var represented by this vertex
const AstSenTree* const m_domainp;
public:
MTaskMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp, const OrderEitherVertex* varp,
const AstSenTree* domainp)
: V3GraphVertex{graphp}
, m_logicp{logicp}
, m_varp{varp}
, m_domainp{domainp} {
UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n");
}
virtual ~MTaskMoveVertex() override = default;
// ACCESSORS
OrderLogicVertex* logicp() const { return m_logicp; }
const OrderEitherVertex* varp() const { return m_varp; }
const AstScope* scopep() const { return m_logicp ? m_logicp->scopep() : nullptr; }
const AstSenTree* domainp() const { return m_domainp; }
virtual string dotColor() const override {
if (logicp()) {
return logicp()->dotColor();
} else {
return "yellow";
}
}
virtual string name() const override {
string nm;
if (logicp()) {
nm = logicp()->name();
nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + " s="
+ cvtToHex(logicp()->scopep())
// "color()" represents the mtask ID.
+ "\\nt=" + cvtToStr(color()));
} else {
nm = "nolog\\nt=" + cvtToStr(color());
}
return nm;
}
};
#endif // Guard

View File

@ -22,6 +22,7 @@
#include "V3Graph.h"
#include "V3OrderGraph.h"
#include "V3OrderMoveGraph.h"
#include <list>
#include <unordered_map>

View File

@ -21,7 +21,7 @@
#include "verilatedos.h"
#include "V3Graph.h"
#include "V3OrderGraph.h"
#include "V3OrderMoveGraph.h"
#include <list>