CTS: improve NDR for clock nets - #11136
Conversation
Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
… clock gaters Signed-off-by: Jonas Gava <jfgava@precisioninno.com>
…ROAD into cts-improve-cg-ndr
There was a problem hiding this comment.
Code Review
This pull request refactors the clock tree level numbering and Non-Default Rule (NDR) application in TritonCTS to support numbering across tree builder boundaries, such as clock gaters, using a global breadth-first traversal. It also updates the default NDR strategy to half and cleans up unused level-tracking variables. A review comment suggests using std::unordered_set instead of std::vector for collecting child nets to avoid duplicate entries and incorrect level increments when a net connects to multiple input pins of the same instance.
| std::vector<odb::dbNet*> childNets; | ||
| for (odb::dbITerm* iterm : net->getITerms()) { | ||
| if (!iterm->isInputSignal()) { | ||
| continue; | ||
| } | ||
| for (odb::dbITerm* outTerm : iterm->getInst()->getITerms()) { | ||
| if (!outTerm->isOutputSignal()) { | ||
| continue; | ||
| } | ||
| odb::dbNet* outNet = outTerm->getNet(); | ||
| if (outNet == nullptr || !treeNets.contains(outNet)) { | ||
| // Not part of a clock tree built by CTS: a sink, or a gater whose | ||
| // fanin was too small for a tree of its own. | ||
| continue; | ||
| } | ||
| if (subTreeRoots.contains(outNet)) { | ||
| feedsSubTree.insert(net); | ||
| } | ||
| childNets.push_back(outNet); | ||
| } |
There was a problem hiding this comment.
Using a std::vector for childNets can lead to duplicate entries if a net connects to multiple input pins of the same instance (e.g., in complex clock gater or clock mux cells). This would cause childNets.size() > 1 to be incorrectly true, falsely incrementing the tree level even when there is no actual branching.
Using a std::unordered_set instead of std::vector ensures that only unique child nets are collected, making the level calculation robust against duplicate pin connections.
std::unordered_set<odb::dbNet*> childNets;
for (odb::dbITerm* iterm : net->getITerms()) {
if (!iterm->isInputSignal()) {
continue;
}
for (odb::dbITerm* outTerm : iterm->getInst()->getITerms()) {
if (!outTerm->isOutputSignal()) {
continue;
}
odb::dbNet* outNet = outTerm->getNet();
if (outNet == nullptr || !treeNets.contains(outNet)) {
// Not part of a clock tree built by CTS: a sink, or a gater whose
// fanin was too small for a tree of its own.
continue;
}
if (subTreeRoots.contains(outNet)) {
feedsSubTree.insert(net);
}
childNets.insert(outNet);
}
}
Summary
Each clock gater spawns its own TreeBuilder, and NDRs were applied per builder, each with its own level numbering restarting at 0, so every gater output net (and every gated subtree's clknet_0) looked like a root and always got the NDR, in all three strategies. The macro/register forked trees had the same problem. Two more defects fell out of it: levels were only tagged on the last subnet of each H-tree segment, so repeater nets inside a trunk (level_ == -1) were skipped even in full; and each builder created a redundant CTS_NDR_n rule.
Type of Change
Impact
computeClockTreeLevels()walks the real clock tree in the DB after all trees are written, numbering levels from the root outward across builder boundaries:A gater (or a forked register tree) is a level boundary: the subtree continues the parent's numbering (gclk1 at level 2, nested gclk2 at level 3 in the test design) instead of being level 0.
Levels count tree levels, not buffer stages — a trunk broken up by repeaters keeps one level, so half never cuts a single trunk in half. Verified against array_max_wl: the computed levels line up exactly with the H-tree topology levels (clknet__*).
A tree's input net shares level 0 with its root buffer's nets, so root_only still covers clk + clknet_0_* as before.
Leaf nets stay excluded, except nets that feed a gater subtree — the tree continues below them, so they count as trunks.
One shared CTS_NDR_0 rule for the whole design instead of one per builder.
Strategies: root_only → level 0; half → levels 0..⌈N/2⌉-1; full → all non-leaf levels. set_debug_level CTS ndr 1 reports the level count, the applied range, and each net with its level.
Example jpeg ihp-sg13g2
root_only
[DEBUG CTS-ndr] Applied NDR to: clk (level 0)
[DEBUG CTS-ndr] Applied NDR to: clknet_0_clk (level 0)
half
[DEBUG CTS-ndr] Applied NDR to: clk (level 0)
[DEBUG CTS-ndr] Applied NDR to: clknet_0_clk (level 0)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_3_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_2_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_1_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_0_0_clk (level 1)
full
[DEBUG CTS-ndr] Applied NDR to: clk (level 0)
[DEBUG CTS-ndr] Applied NDR to: clknet_0_clk (level 0)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_3_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_2_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_1_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_2_0_0_clk (level 1)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_7_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_6_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_5_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_4_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_3_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_2_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_1_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_3_0_0_clk (level 2)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_63_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_62_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_61_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_60_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_59_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_58_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_57_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_56_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_55_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_54_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_53_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_52_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_51_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_50_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_49_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_48_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_47_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_46_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_45_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_44_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_43_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_42_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_41_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_40_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_39_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_38_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_37_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_36_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_35_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_34_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_33_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_32_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_31_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_30_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_29_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_28_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_27_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_26_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_25_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_24_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_23_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_22_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_21_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_20_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_19_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_18_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_17_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_16_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_15_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_14_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_13_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_12_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_11_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_10_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_9_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_8_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_7_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_6_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_5_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_4_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_3_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_2_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_1_0_clk (level 3)
[DEBUG CTS-ndr] Applied NDR to: clknet_6_0_0_clk (level 3)
Verification
./etc/Build.sh).Related Issues
Issue 8579