mirror of
https://github.com/verilator/verilator.git
synced 2025-04-28 03:26:54 +00:00
Internals: Ordering internals realigned with thread branch.
This commit is contained in:
parent
3444dad9ce
commit
2edfe7b8a8
312
src/V3Order.cpp
312
src/V3Order.cpp
@ -103,6 +103,9 @@
|
||||
#include "V3OrderGraph.h"
|
||||
#include "V3EmitV.h"
|
||||
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
class OrderMoveDomScope;
|
||||
|
||||
static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top);
|
||||
@ -410,6 +413,187 @@ public:
|
||||
bool isClkAss() { return m_clkAss; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// ProcessMoveBuildGraph
|
||||
|
||||
template <class T_MoveVertex>
|
||||
class ProcessMoveBuildGraph {
|
||||
// ProcessMoveBuildGraph takes as input the fine-grained graph of
|
||||
// OrderLogicVertex, OrderVarVertex, etc; this is 'm_graph' in
|
||||
// OrderVisitor. It produces a slightly coarsened graph to drive the
|
||||
// code scheduling.
|
||||
//
|
||||
// * The new graph contains nodes of type OrderMoveVertex.
|
||||
//
|
||||
// * The difference in output type is abstracted away by the
|
||||
// 'T_MoveVertex' template parameter.
|
||||
|
||||
// TYPES
|
||||
typedef std::pair<const V3GraphVertex*, const AstSenTree*> VxDomPair;
|
||||
// Maps an (original graph vertex, domain) pair to a T_MoveVertex
|
||||
// Not vl_unordered_map, because std::pair doesn't provide std::hash
|
||||
typedef std::map<VxDomPair, T_MoveVertex*> Var2Move;
|
||||
typedef vl_unordered_map<const OrderLogicVertex*, T_MoveVertex*> Logic2Move;
|
||||
|
||||
public:
|
||||
class MoveVertexMaker {
|
||||
public:
|
||||
// Clients of ProcessMoveBuildGraph must supply MoveVertexMaker
|
||||
// which creates new T_MoveVertex's. Each new vertex wraps lvertexp
|
||||
// (which may be NULL.)
|
||||
virtual T_MoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
|
||||
const OrderEitherVertex* varVertexp,
|
||||
const AstScope* scopep,
|
||||
const AstSenTree* domainp) = 0;
|
||||
virtual void freeVertexp(T_MoveVertex* freeMep) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
const V3Graph* m_graphp; // Input graph of OrderLogicVertex's etc
|
||||
V3Graph* m_outGraphp; // Output graph of T_MoveVertex's
|
||||
MoveVertexMaker* m_vxMakerp; // Factory class for T_MoveVertex's
|
||||
Logic2Move m_logic2move; // Map Logic to Vertex
|
||||
Var2Move m_var2move; // Map Vars to Vertex
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ProcessMoveBuildGraph(const V3Graph* logicGraphp, // Input graph of OrderLogicVertex etc.
|
||||
V3Graph* outGraphp, // Output graph of T_MoveVertex's
|
||||
MoveVertexMaker* vxMakerp)
|
||||
: m_graphp(logicGraphp),
|
||||
m_outGraphp(outGraphp),
|
||||
m_vxMakerp(vxMakerp) {}
|
||||
virtual ~ProcessMoveBuildGraph() {}
|
||||
|
||||
// METHODS
|
||||
void build() {
|
||||
// How this works:
|
||||
// - Create a T_MoveVertex for each OrderLogicVertex.
|
||||
// - Following each OrderLogicVertex, search forward in the context of
|
||||
// its domain...
|
||||
// * If we encounter another OrderLogicVertex in non-exclusive
|
||||
// domain, make the T_MoveVertex->T_MoveVertex edge.
|
||||
// * If we encounter an OrderVarVertex, make a Vertex for the
|
||||
// (OrderVarVertex, domain) pair and continue to search
|
||||
// forward in the context of the same domain. Unless we
|
||||
// already created that pair, in which case, we've already
|
||||
// done the forward search, so stop.
|
||||
|
||||
// For each logic node, make a T_MoveVertex
|
||||
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp;
|
||||
itp=itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
T_MoveVertex* moveVxp =
|
||||
m_vxMakerp->makeVertexp(lvertexp, NULL, lvertexp->scopep(),
|
||||
lvertexp->domainp());
|
||||
if (moveVxp) {
|
||||
// Cross link so we can find it later
|
||||
m_logic2move[lvertexp] = moveVxp;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Build edges between logic vertices
|
||||
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp;
|
||||
itp=itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
T_MoveVertex* moveVxp = m_logic2move[lvertexp];
|
||||
if (moveVxp) {
|
||||
iterate(moveVxp, lvertexp, lvertexp->domainp());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Return true if moveVxp has downstream dependencies
|
||||
bool iterate(T_MoveVertex* moveVxp, const V3GraphVertex* origVxp,
|
||||
const AstSenTree* domainp) {
|
||||
bool madeDeps = false;
|
||||
// Search forward from given original vertex, making new edges from
|
||||
// moveVxp forward
|
||||
for (V3GraphEdge* edgep = origVxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (edgep->weight()==0) { // Was cut
|
||||
continue;
|
||||
}
|
||||
int weight = edgep->weight();
|
||||
if (const OrderLogicVertex* toLVertexp =
|
||||
dynamic_cast<const OrderLogicVertex*>(edgep->top())) {
|
||||
|
||||
// Do not construct dependencies across exclusive domains.
|
||||
if (domainsExclusive(domainp, toLVertexp->domainp())) continue;
|
||||
|
||||
// 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);
|
||||
madeDeps = true;
|
||||
} else {
|
||||
// This is an OrderVarVertex or other vertex representing
|
||||
// data. (Could be var, settle, or input type vertex.)
|
||||
const V3GraphVertex* nonLogicVxp = edgep->top();
|
||||
VxDomPair key(nonLogicVxp, domainp);
|
||||
if (!m_var2move[key]) {
|
||||
const OrderEitherVertex* eithp =
|
||||
dynamic_cast<const OrderEitherVertex*>(nonLogicVxp);
|
||||
T_MoveVertex* newMoveVxp =
|
||||
m_vxMakerp->makeVertexp(NULL, eithp, eithp->scopep(), domainp);
|
||||
m_var2move[key] = newMoveVxp;
|
||||
|
||||
// Find downstream logics that depend on (var, domain)
|
||||
if (!iterate(newMoveVxp, edgep->top(), domainp)) {
|
||||
// No downstream dependencies, so remove this
|
||||
// intermediate vertex.
|
||||
m_var2move[key] = NULL;
|
||||
m_vxMakerp->freeVertexp(newMoveVxp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
madeDeps = true;
|
||||
}
|
||||
}
|
||||
return madeDeps;
|
||||
}
|
||||
VL_UNCOPYABLE(ProcessMoveBuildGraph);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// OrderMoveVertexMaker
|
||||
|
||||
class OrderMoveVertexMaker
|
||||
: public ProcessMoveBuildGraph<OrderMoveVertex>::MoveVertexMaker {
|
||||
// MEMBERS
|
||||
V3Graph* m_pomGraphp;
|
||||
V3List<OrderMoveVertex*>* m_pomWaitingp;
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
OrderMoveVertexMaker(V3Graph* pomGraphp,
|
||||
V3List<OrderMoveVertex*>* pomWaitingp)
|
||||
: m_pomGraphp(pomGraphp),
|
||||
m_pomWaitingp(pomWaitingp) {}
|
||||
// METHODS
|
||||
OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
|
||||
const OrderEitherVertex*,
|
||||
const AstScope* scopep,
|
||||
const AstSenTree* domainp) {
|
||||
OrderMoveVertex* resultp =
|
||||
new OrderMoveVertex(m_pomGraphp, lvertexp);
|
||||
resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep));
|
||||
resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp);
|
||||
return resultp;
|
||||
}
|
||||
void freeVertexp(OrderMoveVertex* freeMep) {
|
||||
freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep);
|
||||
freeMep->unlinkDelete(m_pomGraphp);
|
||||
}
|
||||
private:
|
||||
VL_UNCOPYABLE(OrderMoveVertexMaker);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Order class functions
|
||||
@ -520,8 +704,6 @@ private:
|
||||
void processMove();
|
||||
void processMoveClear();
|
||||
void processMoveBuildGraph();
|
||||
void processMoveBuildGraphIterate (OrderMoveVertex* moveVxp, V3GraphVertex* vertexp, int weightmin);
|
||||
void processMovePrepScopes();
|
||||
void processMovePrepReady();
|
||||
void processMoveReadyOne(OrderMoveVertex* vertexp);
|
||||
void processMoveDoneOne(OrderMoveVertex* vertexp);
|
||||
@ -1044,6 +1226,26 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) {
|
||||
return fromSenListp->edgeType().exclusiveEdge(toSenListp->edgeType());
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// OrderMoveDomScope methods
|
||||
|
||||
// Check the domScope is on ready list, add if not
|
||||
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) {
|
||||
if (!m_onReadyList) {
|
||||
m_onReadyList = true;
|
||||
m_readyDomScopeE.pushBack(ovp->m_pomReadyDomScope, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark one vertex as finished, remove from ready list if done
|
||||
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) {
|
||||
UASSERT(m_onReadyList, "Moving vertex from ready when nothing was on que as ready.");
|
||||
if (m_readyVertices.empty()) { // Else more work to get to later
|
||||
m_onReadyList = false;
|
||||
m_readyDomScopeE.unlink(ovp->m_pomReadyDomScope, this);
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// OrderVisitor - Clock propagation
|
||||
|
||||
@ -1340,60 +1542,10 @@ void OrderVisitor::processMoveBuildGraph() {
|
||||
processMoveClear();
|
||||
m_pomGraph.userClearVertices(); // Vertex::user() // OrderMoveVertex*, last edge added or NULL for none
|
||||
|
||||
// For each logic node, make a graph node
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
OrderMoveVertex* moveVxp = new OrderMoveVertex(&m_pomGraph, lvertexp);
|
||||
moveVxp->m_pomWaitingE.pushBack(m_pomWaiting, moveVxp);
|
||||
// Cross link so we can find it later
|
||||
lvertexp->moveVxp(moveVxp);
|
||||
}
|
||||
}
|
||||
// Build edges between logic vertices
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
OrderMoveVertex* moveVxp = lvertexp->moveVxp();
|
||||
processMoveBuildGraphIterate(moveVxp, lvertexp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OrderVisitor::processMoveBuildGraphIterate (OrderMoveVertex* moveVxp, V3GraphVertex* vertexp, int weightmin) {
|
||||
// Search forward from given logic vertex, making new edges based on moveVxp
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (edgep->weight()!=0) { // was cut
|
||||
int weight = weightmin;
|
||||
if (weight==0 || weight>edgep->weight()) weight=edgep->weight();
|
||||
if (OrderLogicVertex* toLVertexp = dynamic_cast<OrderLogicVertex*>(edgep->top())) {
|
||||
// "Initial" and "settle" domains run at time 0 and never
|
||||
// again. Everything else runs at time >0 and never before.
|
||||
// Ignore deps that cross the time-zero/nonzero boundary.
|
||||
// We'll never run both vertices in the same eval() pass
|
||||
// so there's no need to order them.
|
||||
bool toInitial = (toLVertexp->domainp()->hasInitial()
|
||||
|| toLVertexp->domainp()->hasSettle());
|
||||
bool fromInitial = (moveVxp->logicp()->domainp()->hasInitial()
|
||||
|| moveVxp->logicp()->domainp()->hasSettle());
|
||||
if (toInitial != fromInitial) {
|
||||
continue;
|
||||
}
|
||||
// Sometimes we get deps between 'always @(posedge clk)' and
|
||||
// 'always @(negedge clk)' domains. Discard these. We'll never
|
||||
// evaluate both logic vertices on the same eval() pass so
|
||||
// there's no need to order them.
|
||||
if (domainsExclusive(moveVxp->logicp()->domainp(),
|
||||
toLVertexp->domainp())) {
|
||||
continue;
|
||||
}
|
||||
// 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_pomGraph, moveVxp, toLVertexp->moveVxp(), weight);
|
||||
}
|
||||
else { // Keep hunting forward for a logic node
|
||||
processMoveBuildGraphIterate(moveVxp, edgep->top(), weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
OrderMoveVertexMaker createOrderMoveVertex(&m_pomGraph, &m_pomWaiting);
|
||||
ProcessMoveBuildGraph<OrderMoveVertex> serialPMBG(
|
||||
&m_graph, &m_pomGraph, &createOrderMoveVertex);
|
||||
serialPMBG.build();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
@ -1412,7 +1564,6 @@ void OrderVisitor::processMove() {
|
||||
// Move logic to ordered active
|
||||
// Any children that have all inputs now ready move from waiting->ready graph
|
||||
// (This may add nodes the for loop directly above needs to detext)
|
||||
processMovePrepScopes();
|
||||
processMovePrepReady();
|
||||
|
||||
// New domain... another loop
|
||||
@ -1447,18 +1598,6 @@ void OrderVisitor::processMove() {
|
||||
processMoveClear();
|
||||
}
|
||||
|
||||
void OrderVisitor::processMovePrepScopes() {
|
||||
UINFO(5," MovePrepScopes\n");
|
||||
// Create a OrderMoveDomScope every domain/scope pairing
|
||||
for (OrderMoveVertex* vertexp = m_pomWaiting.begin(); vertexp; vertexp=vertexp->pomWaitingNextp()) {
|
||||
AstSenTree* domainp = vertexp->logicp()->domainp();
|
||||
AstScope* scopep = vertexp->logicp()->scopep();
|
||||
// Create the dom pairing for later lookup
|
||||
OrderMoveDomScope* domScopep = OrderMoveDomScope::findCreate(domainp, scopep);
|
||||
vertexp->domScopep(domScopep);
|
||||
}
|
||||
}
|
||||
|
||||
void OrderVisitor::processMovePrepReady() {
|
||||
// Make list of ready nodes
|
||||
UINFO(5," MovePrepReady\n");
|
||||
@ -1477,17 +1616,25 @@ void OrderVisitor::processMoveReadyOne(OrderMoveVertex* vertexp) {
|
||||
vertexp->setReady();
|
||||
// Remove node from waiting list
|
||||
vertexp->m_pomWaitingE.unlink(m_pomWaiting, vertexp);
|
||||
// Add to ready list (indexed by domain and scope)
|
||||
vertexp->m_readyVerticesE.pushBack(vertexp->domScopep()->m_readyVertices, vertexp);
|
||||
vertexp->domScopep()->ready(this);
|
||||
if (vertexp->logicp()) {
|
||||
// Add to ready list (indexed by domain and scope)
|
||||
vertexp->m_readyVerticesE.pushBack(vertexp->domScopep()->m_readyVertices, vertexp);
|
||||
vertexp->domScopep()->ready(this);
|
||||
} else {
|
||||
// vertexp represents a non-logic vertex.
|
||||
// Recurse to mark its following neighbors ready.
|
||||
processMoveDoneOne(vertexp);
|
||||
}
|
||||
}
|
||||
|
||||
void OrderVisitor::processMoveDoneOne(OrderMoveVertex* vertexp) {
|
||||
// Move one node from ready to completion
|
||||
vertexp->setMoved();
|
||||
// Unlink from ready lists
|
||||
vertexp->m_readyVerticesE.unlink(vertexp->domScopep()->m_readyVertices, vertexp);
|
||||
vertexp->domScopep()->movedVertex(this, vertexp);
|
||||
if (vertexp->logicp()) {
|
||||
vertexp->m_readyVerticesE.unlink(vertexp->domScopep()->m_readyVertices, vertexp);
|
||||
vertexp->domScopep()->movedVertex(this, vertexp);
|
||||
}
|
||||
// Don't need to add it to another list, as we're done with it
|
||||
// Mark our outputs as one closer to ready
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(), *nextp; edgep; edgep=nextp) {
|
||||
@ -1573,23 +1720,6 @@ AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp,
|
||||
return activep;
|
||||
}
|
||||
|
||||
// Check the domScope is on ready list, add if not
|
||||
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) {
|
||||
if (!m_onReadyList) {
|
||||
m_onReadyList = true;
|
||||
m_readyDomScopeE.pushBack(ovp->m_pomReadyDomScope, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark one vertex as finished, remove from ready list if done
|
||||
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) {
|
||||
UASSERT(m_onReadyList, "Moving vertex from ready when nothing was on que as ready.");
|
||||
if (m_readyVertices.empty()) { // Else more work to get to later
|
||||
m_onReadyList = false;
|
||||
m_readyDomScopeE.unlink(ovp->m_pomReadyDomScope, this);
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// OrderVisitor - Top processing
|
||||
|
||||
|
@ -50,6 +50,7 @@
|
||||
|
||||
class OrderVisitor;
|
||||
class OrderMoveVertex;
|
||||
class OrderMoveVertexMaker;
|
||||
class OrderMoveDomScope;
|
||||
|
||||
//######################################################################
|
||||
@ -188,13 +189,12 @@ public:
|
||||
|
||||
class OrderLogicVertex : public OrderEitherVertex {
|
||||
AstNode* m_nodep;
|
||||
OrderMoveVertex* m_moveVxp;
|
||||
protected:
|
||||
OrderLogicVertex(V3Graph* graphp, const OrderLogicVertex& old)
|
||||
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep), m_moveVxp(old.m_moveVxp) {}
|
||||
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep) {}
|
||||
public:
|
||||
OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep)
|
||||
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep), m_moveVxp(NULL) {}
|
||||
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep) {}
|
||||
virtual ~OrderLogicVertex() {}
|
||||
virtual OrderLogicVertex* clone(V3Graph* graphp) const {
|
||||
return new OrderLogicVertex(graphp, *this); }
|
||||
@ -204,8 +204,6 @@ public:
|
||||
virtual string name() const { return (cvtToStr((void*)m_nodep)+"\\n "+cvtToStr(nodep()->typeName())); }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
virtual string dotColor() const { return "yellow"; }
|
||||
OrderMoveVertex* moveVxp() const { return m_moveVxp; }
|
||||
void moveVxp(OrderMoveVertex* moveVxp) { m_moveVxp = moveVxp; }
|
||||
};
|
||||
|
||||
class OrderVarVertex : public OrderEitherVertex {
|
||||
@ -315,21 +313,18 @@ class OrderMoveVertex : public V3GraphVertex {
|
||||
|
||||
protected:
|
||||
friend class OrderVisitor;
|
||||
friend class OrderMoveVertexMaker;
|
||||
// These only contain the "next" item,
|
||||
// for the head of the list, see the same var name under OrderVisitor
|
||||
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
|
||||
V3ListEnt<OrderMoveVertex*> m_readyVerticesE;// List of ready under domain/scope
|
||||
// CONSTRUCTORS
|
||||
OrderMoveVertex(V3Graph* graphp, const OrderMoveVertex& old)
|
||||
: V3GraphVertex(graphp, old), m_logicp(old.m_logicp), m_state(old.m_state)
|
||||
, m_domScopep(old.m_domScopep) {}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
|
||||
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
|
||||
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
|
||||
virtual ~OrderMoveVertex() {}
|
||||
virtual OrderMoveVertex* clone(V3Graph* graphp) const {
|
||||
return new OrderMoveVertex(graphp, *this);
|
||||
}
|
||||
v3fatalSrc("Unsupported"); return NULL; }
|
||||
// METHODS
|
||||
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; }
|
||||
virtual string dotColor() const {
|
||||
|
Loading…
Reference in New Issue
Block a user