Fix interface exposure with --public-depth or --trace-depth (#5758).

This commit is contained in:
Wilson Snyder
2025-09-23 22:05:51 -04:00
parent d972b7465a
commit fd12ab3413
17 changed files with 225 additions and 14 deletions
+5 -2
View File
@@ -293,7 +293,8 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module.
// Used for user messages only.
string m_libname; // Work library
int m_level = 0; // 1=top module, 2=cell off top module, ...
int m_depth = 0; // 1=top module, 2=cell off top, shared things low, for -depth options
int m_level = 0; // 1=top module, 2=cell off top, shared things have high number
VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
@@ -341,7 +342,9 @@ public:
void someInstanceName(const string& name) { m_someInstanceName = name; }
bool inLibrary() const { return m_inLibrary; }
void inLibrary(bool flag) { m_inLibrary = flag; }
void level(int level) { m_level = level; }
void depth(int value) { m_depth = value; }
int depth() const VL_MT_SAFE { return m_depth; }
void level(int value) { m_level = value; }
int level() const VL_MT_SAFE { return m_level; }
string libname() const { return m_libname; }
string prettyLibnameQ() const { return "'" + prettyName(libname()) + "'"; }
+1
View File
@@ -2419,6 +2419,7 @@ void AstNetlist::createTopScope(AstScope* scopep) {
void AstNodeModule::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " L" << level();
str << " D" << depth();
if (modPublic()) str << " [P]";
if (inLibrary()) str << " [LIB]";
if (dead()) str << " [DEAD]";
+9
View File
@@ -201,6 +201,7 @@ class V3GraphVertex VL_NOT_FINAL {
friend class V3GraphEdge;
friend class GraphAcyc;
friend class GraphAlgRank;
friend class GraphAlgRankDepth;
V3ListLinks<V3GraphVertex> m_links; // List links to store instances of this class
V3GraphEdge::OList m_outs; // List of outbound edges
V3GraphEdge::IList m_ins; // List of inbound edges
@@ -382,11 +383,19 @@ public:
void stronglyConnected(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED;
/// Assign an ordering number to all vertexes in a tree.
/// For multiple usages of a vertex, get the maximum of all inbound ranks + 1
/// All nodes with no inputs will get rank 1
/// Side-effect: changes user()
void rank(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED;
void rank() VL_MT_DISABLED;
/// Assign an ordering number to all vertexes in a tree.
/// For multiple usages of a vertex, get the minimu of all inbound ranks + 1
/// All nodes with no inputs will get rank 1
/// Side-effect: changes user()
void rankMin(V3EdgeFuncP edgeFuncp) VL_MT_DISABLED;
void rankMin() VL_MT_DISABLED;
/// Sort all vertices and edges using the V3GraphVertex::sortCmp() function
void sortVertices() VL_MT_DISABLED;
/// Sort all edges and edges using the V3GraphEdge::sortCmp() function
+56 -6
View File
@@ -271,12 +271,9 @@ class GraphAlgRank final : GraphAlg<> {
vertex.user(0);
}
for (V3GraphVertex& vertex : m_graphp->vertices()) {
if (!vertex.user()) { //
vertexIterate(&vertex, 1);
}
if (!vertex.user()) vertexIterate(&vertex, 1);
}
}
void vertexIterate(V3GraphVertex* vertexp, uint32_t currentRank) {
// Assign rank to each unvisited node
// If larger rank is found, assign it and loop back through
@@ -302,10 +299,63 @@ public:
~GraphAlgRank() = default;
};
void V3Graph::rank() { GraphAlgRank{this, &V3GraphEdge::followAlwaysTrue}; }
void V3Graph::rank() { rank(&V3GraphEdge::followAlwaysTrue); }
void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank{this, edgeFuncp}; }
//######################################################################
//######################################################################
// Algorithms - ranking min
// Changes user() and rank()
class GraphAlgRankMin final : GraphAlg<> {
void main() {
// Rank each vertex, ignoring cutable edges
// Vertex::m_user begin: 1 indicates processing, 2 indicates completed
// Clear existing ranks
for (V3GraphVertex& vertex : m_graphp->vertices()) {
vertex.rank(0);
vertex.user(0);
}
for (V3GraphVertex& vertex : m_graphp->vertices()) {
if (!vertex.user()) vertexIterate(&vertex);
}
}
uint32_t vertexIterate(V3GraphVertex* vertexp) {
// Assign rank to each unvisited node
// If we hit a back node make a list of all loops
if (vertexp->user() == 1) {
m_graphp->loopsMessageCb(vertexp, m_edgeFuncp);
return vertexp->rank();
}
if (vertexp->user()) return vertexp->rank(); // Done earlier
vertexp->user(1);
vertexp->rank(1); // In case loop
// If no input edges, then rank 1 (+ adder)
// Otherwise, get minimum from following all inputs.
uint32_t minrank = ~0U;
for (V3GraphEdge& edge : vertexp->inEdges()) {
if (followEdge(&edge)) {
const uint32_t nrank = vertexIterate(edge.fromp());
minrank = std::min(minrank, nrank);
}
}
if (minrank == ~0U) minrank = 0;
vertexp->rank(minrank + vertexp->rankAdder());
vertexp->user(2);
return vertexp->rank();
}
public:
GraphAlgRankMin(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>{graphp, edgeFuncp} {
main();
}
~GraphAlgRankMin() = default;
};
void V3Graph::rankMin() { rankMin(&V3GraphEdge::followAlwaysTrue); }
void V3Graph::rankMin(V3EdgeFuncP edgeFuncp) { GraphAlgRankMin{this, edgeFuncp}; }
//######################################################################
//######################################################################
// Algorithms - report loops
+8
View File
@@ -205,6 +205,14 @@ class LinkCellsVisitor final : public VNVisitor {
modp->level(vvertexp->rank() + 1);
}
}
m_graph.rankMin();
for (V3GraphVertex& vtx : m_graph.vertices()) {
if (const LinkCellsVertex* const vvertexp = vtx.cast<LinkCellsVertex>()) {
// +1 so we leave level 1 for the new wrapper we'll make in a moment
AstNodeModule* const modp = vvertexp->modp();
modp->depth(vvertexp->rank() + 1);
}
}
if (v3Global.opt.topModule() != "" && !m_topVertexp) {
v3error("Specified --top-module '" << v3Global.opt.topModule()
<< "' was not found in design.");
+1
View File
@@ -173,6 +173,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
// Make the new module first in the list
oldmodp->unlinkFrBackWithNext();
newmodp->addNext(oldmodp);
newmodp->depth(1);
newmodp->level(1);
newmodp->modPublic(true);
newmodp->protect(false);
+2 -2
View File
@@ -354,7 +354,7 @@ class LinkParseVisitor final : public VNVisitor {
} else if (v3Global.opt.publicParams() && nodep->isParam()) {
nodep->sigUserRWPublic(true);
} else if (m_modp && v3Global.opt.publicDepth()) {
if ((m_modp->level() - 1) <= v3Global.opt.publicDepth()) {
if ((m_modp->depth() - 1) <= v3Global.opt.publicDepth()) {
nodep->sigUserRWPublic(true);
} else if (VN_IS(m_modp, Package) && nodep->isParam()) {
nodep->sigUserRWPublic(true);
@@ -365,7 +365,7 @@ class LinkParseVisitor final : public VNVisitor {
// We used modTrace before leveling, and we may now
// want to turn it off now that we know the levelizations
if (v3Global.opt.traceDepth() && m_modp
&& (m_modp->level() - 1) > v3Global.opt.traceDepth()) {
&& (m_modp->depth() - 1) > v3Global.opt.traceDepth()) {
m_modp->modTrace(false);
nodep->trace(false);
}
+3
View File
@@ -1761,6 +1761,9 @@ class ParamTop final : VNDeleter {
maxParentLevel = std::max(maxParentLevel, parentp->level());
}
if (modp->level() <= maxParentLevel) modp->level(maxParentLevel + 1);
// Not correct fixup of depth(), as it should be mininum. But depth() is unused
// past V3LinkParse, so just do something sane in case this code doesn't get updated
modp->depth(modp->level());
}
void resortNetlistModules(AstNetlist* netlistp) {