Skip to content

Commit d88fb03

Browse files
committed
cts: new way to get clock tree level for each net
Signed-off-by: Jonas Gava <[email protected]>
1 parent 08a1a86 commit d88fb03

File tree

5 files changed

+159
-103
lines changed

5 files changed

+159
-103
lines changed

src/cts/include/cts/TritonCTS.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,13 @@ class TritonCTS
9898
std::vector<int> getAllClockTreeLevels(
9999
odb::dbBlock* block_,
100100
const std::set<odb::dbNet*>& clkLeafNets);
101-
int applyNDRToClockLevels(odb::dbBlock* block_,
102-
odb::dbTechNonDefaultRule* clockNDR,
103-
const std::set<odb::dbNet*>& clkLeafNets,
104-
const std::vector<int>& targetLevels);
101+
int applyNDRToClockLevels(Clock& clockNet, odb::dbTechNonDefaultRule* clockNDR, const std::vector<int>& targetLevels);
102+
103+
// int applyNDRToClockLevels(Clock& clockNet,
104+
// odb::dbBlock* block_,
105+
// odb::dbTechNonDefaultRule* clockNDR,
106+
// const std::set<odb::dbNet*>& clkLeafNets,
107+
// const std::vector<int>& targetLevels);
105108
int applyNDRToClockLevelRange(odb::dbBlock* block_,
106109
odb::dbTechNonDefaultRule* clockNDR,
107110
const std::set<odb::dbNet*>& clkLeafNets,
@@ -116,7 +119,7 @@ class TritonCTS
116119
void populateTritonCTS();
117120
void writeClockNetsToDb(TreeBuilder* builder,
118121
std::set<odb::dbNet*>& clkLeafNets);
119-
void writeClockNDRsToDb(const std::set<odb::dbNet*>& clkLeafNets);
122+
void writeClockNDRsToDb(TreeBuilder* builder, const std::set<odb::dbNet*>& clkLeafNets);
120123
void incrementNumClocks() { ++numberOfClocks_; }
121124
void clearNumClocks() { numberOfClocks_ = 0; }
122125
unsigned getNumClocks() const { return numberOfClocks_; }

src/cts/src/Clock.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,16 @@ class ClockSubNet
9494
std::deque<ClockInst*> instances_;
9595
std::unordered_map<ClockInst*, unsigned> mapInstToIdx_;
9696
bool leafLevel_ = false;
97+
int level_ = -1;
98+
odb::dbNet* netObj_ = nullptr;
9799

98100
public:
99101
explicit ClockSubNet(const std::string& name) : name_(name) {}
100102

103+
void setNetObj(odb::dbNet* net) { netObj_ = net; }
104+
odb::dbNet* getNetObj() { return netObj_; }
105+
void setTreeLevel(int level) { level_ = level; }
106+
int getTreeLevel() { return level_; }
101107
void setLeafLevel(bool isLeaf) { leafLevel_ = isLeaf; }
102108
bool isLeafLevel() const { return leafLevel_; }
103109

src/cts/src/HTreeBuilder.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ void HTreeBuilder::preSinkClustering(
222222
for (ClockInst* clockInstObj : clusterClockInsts) {
223223
clockSubNet.addInst(*clockInstObj);
224224
}
225+
clockSubNet.setTreeLevel(0);
225226
if (!secondLevel) {
226227
clockSubNet.setLeafLevel(true);
227228
}
@@ -1849,6 +1850,7 @@ void HTreeBuilder::createClockSubNets()
18491850

18501851
addTreeLevelBuffer(&rootBuffer);
18511852
ClockSubNet& rootClockSubNet = clock_.addSubNet("clknet_0");
1853+
rootClockSubNet.setTreeLevel(0);
18521854
rootClockSubNet.addInst(rootBuffer);
18531855
treeBufLevels_++;
18541856

@@ -1949,6 +1951,10 @@ void HTreeBuilder::createClockSubNets()
19491951
*techChar_,
19501952
wireSegmentUnit_,
19511953
this);
1954+
1955+
// Set clock tree level the first time only.
1956+
if (builder.getSubNetTreeLevel() < 0)
1957+
builder.setSubNetTreeLevel(levelIdx);
19521958

19531959
if (!options_->getTreeBuffer().empty()) {
19541960
builder.build(options_->getTreeBuffer());
@@ -2017,6 +2023,7 @@ void HTreeBuilder::createSingleBufferClockNet()
20172023

20182024
addTreeLevelBuffer(&rootBuffer);
20192025
ClockSubNet& clockSubNet = clock_.addSubNet("clknet_0");
2026+
clockSubNet.setTreeLevel(0);
20202027
clockSubNet.addInst(rootBuffer);
20212028

20222029
clock_.forEachSink([&](ClockInst& inst) { clockSubNet.addInst(inst); });

src/cts/src/HTreeBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class SegmentBuilder
3838
ClockSubNet* getDrivingSubNet() const { return drivingSubNet_; }
3939
unsigned getNumBufferLevels() const { return numBufferLevels_; }
4040
TreeBuilder* getTree() const { return tree_; }
41+
void setSubNetTreeLevel(int level){drivingSubNet_->setTreeLevel(level);}
42+
int getSubNetTreeLevel(){return drivingSubNet_->getTreeLevel();}
4143

4244
private:
4345
const std::string instPrefix_;

src/cts/src/TritonCTS.cpp

Lines changed: 136 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ void TritonCTS::writeDataToDb()
474474
for (auto& builder : builders_) {
475475
writeClockNetsToDb(builder.get(), clkLeafNets);
476476
if (options_->applyNDR()) {
477-
writeClockNDRsToDb(clkLeafNets);
477+
writeClockNDRsToDb(builder.get(), clkLeafNets);
478478
}
479479
if (options_->dummyLoadEnabled()) {
480480
writeDummyLoadsToDb(builder->getClock(), clkDummies);
@@ -1419,6 +1419,7 @@ void TritonCTS::writeClockNetsToDb(TreeBuilder* builder,
14191419
}
14201420
odb::dbNet* clkSubNet
14211421
= odb::dbNet::create(block_, subNet.getName().c_str());
1422+
subNet.setNetObj(clkSubNet);
14221423

14231424
++numClkNets_;
14241425
clkSubNet->setSigType(odb::dbSigType::CLOCK);
@@ -1539,44 +1540,43 @@ void TritonCTS::writeClockNetsToDb(TreeBuilder* builder,
15391540
}
15401541

15411542
// Function to extract level number from clock net name
1542-
int TritonCTS::extractClockTreeLevelFromNetName(const std::string& netName)
1543-
{
1544-
// Pattern to find number between underscores (e.g., "clknet_2_clk_i")
1545-
std::regex pattern("_([0-9]+)_");
1546-
std::smatch match;
1547-
1548-
if (std::regex_search(netName, match, pattern)) {
1549-
return std::stoi(match[1]);
1550-
}
1551-
1552-
// If no number found between underscores, it's level 0
1553-
return 0;
1554-
}
1555-
1556-
// Utility function to get all unique clock tree levels in the design
1557-
std::vector<int> TritonCTS::getAllClockTreeLevels(
1558-
odb::dbBlock* block_,
1559-
const std::set<odb::dbNet*>& clkLeafNets)
1560-
{
1561-
std::set<int> uniqueLevels;
1562-
1563-
for (odb::dbNet* net : block_->getNets()) {
1564-
if (net->getSigType() == odb::dbSigType::CLOCK
1565-
&& (clkLeafNets.find(net) == clkLeafNets.end())) {
1566-
int level = extractClockTreeLevelFromNetName(net->getConstName());
1567-
uniqueLevels.insert(level);
1568-
}
1569-
}
1570-
1571-
return std::vector<int>(uniqueLevels.begin(), uniqueLevels.end());
1572-
;
1573-
}
1543+
// int TritonCTS::extractClockTreeLevelFromNetName(const std::string& netName)
1544+
// {
1545+
// // Pattern to find number between underscores (e.g., "clknet_2_clk_i")
1546+
// std::regex pattern("_([0-9]+)_");
1547+
// std::smatch match;
1548+
1549+
// if (std::regex_search(netName, match, pattern)) {
1550+
// return std::stoi(match[1]);
1551+
// }
1552+
1553+
// // If no number found between underscores, it's level 0
1554+
// return 0;
1555+
// }
1556+
1557+
// // Utility function to get all unique clock tree levels in the design
1558+
// std::vector<int> TritonCTS::getAllClockTreeLevels(
1559+
// odb::dbBlock* block_,
1560+
// const std::set<odb::dbNet*>& clkLeafNets)
1561+
// {
1562+
// std::set<int> uniqueLevels;
1563+
1564+
// for (odb::dbNet* net : block_->getNets()) {
1565+
// if (net->getSigType() == odb::dbSigType::CLOCK
1566+
// && (clkLeafNets.find(net) == clkLeafNets.end())) {
1567+
// int level = extractClockTreeLevelFromNetName(net->getConstName());
1568+
// uniqueLevels.insert(level);
1569+
// }
1570+
// }
1571+
1572+
// return std::vector<int>(uniqueLevels.begin(), uniqueLevels.end());
1573+
// ;
1574+
// }
15741575

15751576
// Function to apply NDR to specific clock tree levels and return the number of
15761577
// NDR applied nets
1577-
int TritonCTS::applyNDRToClockLevels(odb::dbBlock* block_,
1578+
int TritonCTS::applyNDRToClockLevels(Clock& clockNet,
15781579
odb::dbTechNonDefaultRule* clockNDR,
1579-
const std::set<odb::dbNet*>& clkLeafNets,
15801580
const std::vector<int>& targetLevels)
15811581
{
15821582
int ndrAppliedNets = 0;
@@ -1587,75 +1587,114 @@ int TritonCTS::applyNDRToClockLevels(odb::dbBlock* block_,
15871587
debugPrint(logger_, CTS, "clustering", 1, "{} ", level);
15881588
}
15891589

1590-
// Single pass: check clock nets and apply NDR if level matches
1591-
for (odb::dbNet* net : block_->getNets()) {
1592-
if (net->getSigType() == odb::dbSigType::CLOCK
1593-
&& (clkLeafNets.find(net) == clkLeafNets.end())) {
1594-
const std::string netName = net->getConstName();
1595-
const int level = extractClockTreeLevelFromNetName(netName);
1596-
1597-
// Apply NDR if this level is in the target list
1598-
if (std::find(targetLevels.begin(), targetLevels.end(), level)
1599-
!= targetLevels.end()) {
1590+
// Check if the main clock net (level 0) is in the level list
1591+
if (std::find(targetLevels.begin(), targetLevels.end(), 0)
1592+
!= targetLevels.end())
1593+
{
1594+
odb::dbNet* clk_net = clockNet.getNetObj();
1595+
clk_net->setNonDefaultRule(clockNDR);
1596+
ndrAppliedNets++;
1597+
// clang-format off
1598+
debugPrint(logger_, CTS, "clustering", 1,
1599+
"Applied NDR to: {} (level {})", clockNet.getName(), 0);
1600+
// clang-format on
1601+
}
1602+
1603+
////////////////////////////////////
1604+
// Check clock sub nets list and apply NDR if level matches
1605+
clockNet.forEachSubNet([&](ClockSubNet& subNet) {
1606+
int level = subNet.getTreeLevel();
1607+
if(!subNet.isLeafLevel())
1608+
logger_->report("Net {} - Level: {}",subNet.getName(), level);
1609+
if (std::find(targetLevels.begin(), targetLevels.end(), level)
1610+
!= targetLevels.end())
1611+
{
1612+
odb::dbNet* net = subNet.getNetObj();
1613+
if (!subNet.isLeafLevel())
1614+
{
16001615
net->setNonDefaultRule(clockNDR);
16011616
ndrAppliedNets++;
1617+
std::string net_name = net->getName();
16021618
// clang-format off
16031619
debugPrint(logger_, CTS, "clustering", 1,
1604-
"Applied NDR to: {} (level {})", netName, level);
1620+
"Applied NDR to: {} (level {})", net_name, level);
16051621
// clang-format on
16061622
}
16071623
}
1608-
}
1609-
1610-
return ndrAppliedNets;
1611-
}
1612-
1613-
// Alternative function to apply NDR to a range of clock tree levels
1614-
int TritonCTS::applyNDRToClockLevelRange(
1615-
odb::dbBlock* block_,
1616-
odb::dbTechNonDefaultRule* clockNDR,
1617-
const std::set<odb::dbNet*>& clkLeafNets,
1618-
const int minLevel,
1619-
const int maxLevel)
1620-
{
1621-
std::vector<int> targetLevels;
1622-
for (int i = minLevel; i <= maxLevel; i++) {
1623-
targetLevels.push_back(i);
1624-
}
1625-
1626-
return applyNDRToClockLevels(block_, clockNDR, clkLeafNets, targetLevels);
1627-
}
1628-
1629-
// Function to apply NDR to the first half of clock tree levels
1630-
int TritonCTS::applyNDRToFirstHalfLevels(
1631-
odb::dbBlock* block_,
1632-
odb::dbTechNonDefaultRule* clockNDR,
1633-
const std::set<odb::dbNet*>& clkLeafNets)
1634-
{
1635-
// Get all unique levels in the design
1636-
const std::vector<int> allLevels = getAllClockTreeLevels(block_, clkLeafNets);
1637-
1638-
// Calculate first half (rounding up if odd number of levels)
1639-
const size_t halfCount = (allLevels.size() + 1) / 2;
1624+
});
16401625

1641-
// Create vector with first half of levels
1642-
std::vector<int> firstHalfLevels(allLevels.begin(),
1643-
allLevels.begin() + halfCount);
1626+
//////////////////////////////////////
16441627

1645-
// clang-format off
1646-
debugPrint(logger_, CTS, "clustering", 1, "Total clock tree levels found: {}"
1647-
"Applying NDR to first {} levels", allLevels.size(), halfCount);
1648-
// clang-format on
1628+
// Single pass: check clock nets and apply NDR if level matches
1629+
// for (odb::dbNet* net : block_->getNets()) {
1630+
// if (net->getSigType() == odb::dbSigType::CLOCK
1631+
// && (clkLeafNets.find(net) == clkLeafNets.end())) {
1632+
// const std::string netName = net->getConstName();
1633+
// const int level = extractClockTreeLevelFromNetName(netName);
1634+
1635+
// // Apply NDR if this level is in the target list
1636+
// if (std::find(targetLevels.begin(), targetLevels.end(), level)
1637+
// != targetLevels.end()) {
1638+
// net->setNonDefaultRule(clockNDR);
1639+
// ndrAppliedNets++;
1640+
// // clang-format off
1641+
// debugPrint(logger_, CTS, "clustering", 1,
1642+
// "Applied NDR to: {} (level {})", netName, level);
1643+
// // clang-format on
1644+
// }
1645+
// }
1646+
// }
16491647

1650-
// Apply NDR to the first half
1651-
return applyNDRToClockLevels(block_, clockNDR, clkLeafNets, firstHalfLevels);
1648+
return ndrAppliedNets;
16521649
}
16531650

1654-
void TritonCTS::writeClockNDRsToDb(const std::set<odb::dbNet*>& clkLeafNets)
1651+
// Alternative function to apply NDR to a range of clock tree levels
1652+
// int TritonCTS::applyNDRToClockLevelRange(
1653+
// odb::dbBlock* block_,
1654+
// odb::dbTechNonDefaultRule* clockNDR,
1655+
// const std::set<odb::dbNet*>& clkLeafNets,
1656+
// const int minLevel,
1657+
// const int maxLevel)
1658+
// {
1659+
// std::vector<int> targetLevels;
1660+
// for (int i = minLevel; i <= maxLevel; i++) {
1661+
// targetLevels.push_back(i);
1662+
// }
1663+
1664+
// return applyNDRToClockLevels(block_, clockNDR, clkLeafNets, targetLevels);
1665+
// }
1666+
1667+
// // Function to apply NDR to the first half of clock tree levels
1668+
// int TritonCTS::applyNDRToFirstHalfLevels(
1669+
// odb::dbBlock* block_,
1670+
// odb::dbTechNonDefaultRule* clockNDR,
1671+
// const std::set<odb::dbNet*>& clkLeafNets)
1672+
// {
1673+
// // Get all unique levels in the design
1674+
// const std::vector<int> allLevels = getAllClockTreeLevels(block_, clkLeafNets);
1675+
1676+
// // Calculate first half (rounding up if odd number of levels)
1677+
// const size_t halfCount = (allLevels.size() + 1) / 2;
1678+
1679+
// // Create vector with first half of levels
1680+
// std::vector<int> firstHalfLevels(allLevels.begin(),
1681+
// allLevels.begin() + halfCount);
1682+
1683+
// // clang-format off
1684+
// debugPrint(logger_, CTS, "clustering", 1, "Total clock tree levels found: {}"
1685+
// "Applying NDR to first {} levels", allLevels.size(), halfCount);
1686+
// // clang-format on
1687+
1688+
// // Apply NDR to the first half
1689+
// return applyNDRToClockLevels(block_, clockNDR, clkLeafNets, firstHalfLevels);
1690+
// }
1691+
1692+
void TritonCTS::writeClockNDRsToDb(TreeBuilder* builder, const std::set<odb::dbNet*>& clkLeafNets)
16551693
{
16561694
char ruleName[64];
16571695
int ruleIndex = 0;
16581696
odb::dbTechNonDefaultRule* clockNDR;
1697+
Clock& clockNet = builder->getClock();
16591698

16601699
// create a new non-default rule in *block* not tech
16611700
while (ruleIndex >= 0) {
@@ -1693,9 +1732,8 @@ void TritonCTS::writeClockNDRsToDb(const std::set<odb::dbNet*>& clkLeafNets)
16931732

16941733
// TODO: Add user specified args to choose the NDR strategy
16951734
// Option 1: Apply NDR to specific levels
1696-
// std::vector<int> specificLevels = {0}; // Apply to level 0
1697-
// clkNets = applyNDRToClockLevels(block_, clockNDR, clkLeafNets,
1698-
// specificLevels);
1735+
std::vector<int> specificLevels = {0,1,2}; // Apply to level 0
1736+
clkNets = applyNDRToClockLevels(clockNet, clockNDR, specificLevels);
16991737

17001738
// Option 2: Apply NDR to a range of levels (e.g., Levels 0-3)
17011739
// clkNets = applyNDRToClockLevelRange(block_, clockNDR, clkLeafNets, 0, 3);
@@ -1705,13 +1743,13 @@ void TritonCTS::writeClockNDRsToDb(const std::set<odb::dbNet*>& clkLeafNets)
17051743
// clkNets = applyNDRToFirstHalfLevels(block_, clockNDR, clkLeafNets);
17061744

17071745
// Option 4: Apply NDR to all non-leaf clock nets (default)
1708-
for (odb::dbNet* net : block_->getNets()) {
1709-
if (net->getSigType() == odb::dbSigType::CLOCK
1710-
&& (clkLeafNets.find(net) == clkLeafNets.end())) {
1711-
net->setNonDefaultRule(clockNDR);
1712-
clkNets++;
1713-
}
1714-
}
1746+
// for (odb::dbNet* net : block_->getNets()) {
1747+
// if (net->getSigType() == odb::dbSigType::CLOCK
1748+
// && (clkLeafNets.find(net) == clkLeafNets.end())) {
1749+
// net->setNonDefaultRule(clockNDR);
1750+
// clkNets++;
1751+
// }
1752+
// }
17151753

17161754
logger_->info(CTS,
17171755
202,

0 commit comments

Comments
 (0)