Skip to content

Commit 90f1d9c

Browse files
authored
Merge pull request #9130 from The-OpenROAD-Project-staging/secure-fix-repair-clock-nets
cts, rsz: `Resizer::repairClkNets()` infers if the clock buffer list is empty.
2 parents 5e8f15c + d2ebf62 commit 90f1d9c

File tree

12 files changed

+312
-210
lines changed

12 files changed

+312
-210
lines changed

src/cts/include/cts/TritonCTS.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,10 @@ class TritonCTS
8181
void setSinkBuffer(const char* buffers);
8282

8383
private:
84-
bool isClockCellCandidate(sta::LibertyCell* cell);
8584
std::string selectRootBuffer(std::vector<std::string>& buffers);
8685
std::string selectSinkBuffer(std::vector<std::string>& buffers);
8786
std::string selectBestMaxCapBuffer(const std::vector<std::string>& buffers,
8887
float totalCap);
89-
void inferBufferList(std::vector<std::string>& buffers);
9088
TreeBuilder* addBuilder(CtsOptions* options,
9189
Clock& net,
9290
odb::dbNet* topInputNet,

src/cts/src/TritonCTS.cpp

Lines changed: 8 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,10 @@ void TritonCTS::setBufferList(const char* buffers)
660660
std::vector<std::string> bufferList(begin, end);
661661
// If the vector is empty, then the buffers are inferred
662662
if (bufferList.empty()) {
663-
inferBufferList(bufferList);
663+
const char* lib_name
664+
= options_->isCtsLibrarySet() ? options_->getCtsLibrary() : nullptr;
665+
resizer_->inferClockBufferList(lib_name, bufferList);
666+
options_->setBufferListInferred(true);
664667
} else {
665668
// Iterate the user-defined buffer list
666669
sta::Vector<sta::LibertyCell*> selected_buffers;
@@ -684,169 +687,6 @@ void TritonCTS::setBufferList(const char* buffers)
684687
options_->setBufferList(bufferList);
685688
}
686689

687-
void TritonCTS::inferBufferList(std::vector<std::string>& buffers)
688-
{
689-
sta::Vector<sta::LibertyCell*> selected_buffers;
690-
691-
// first, look for buffers with "is_clock_cell: true" cell attribute
692-
sta::LibertyLibraryIterator* lib_iter = network_->libertyLibraryIterator();
693-
while (lib_iter->hasNext()) {
694-
sta::LibertyLibrary* lib = lib_iter->next();
695-
if (options_->isCtsLibrarySet()
696-
&& strcmp(lib->name(), options_->getCtsLibrary()) != 0) {
697-
continue;
698-
}
699-
for (sta::LibertyCell* buffer : *lib->buffers()) {
700-
if (buffer->isClockCell() && isClockCellCandidate(buffer)) {
701-
// "is_clock_cell: true"
702-
selected_buffers.emplace_back(buffer);
703-
debugPrint(logger_,
704-
CTS,
705-
"buffering",
706-
1,
707-
"{} has clock cell attribute",
708-
buffer->name());
709-
}
710-
}
711-
}
712-
delete lib_iter;
713-
714-
// second, look for buffers with an input port that has
715-
// LEF USE as "CLOCK"
716-
if (selected_buffers.empty()) {
717-
sta::LibertyLibraryIterator* lib_iter = network_->libertyLibraryIterator();
718-
while (lib_iter->hasNext()) {
719-
sta::LibertyLibrary* lib = lib_iter->next();
720-
if (options_->isCtsLibrarySet()
721-
&& strcmp(lib->name(), options_->getCtsLibrary()) != 0) {
722-
continue;
723-
}
724-
for (sta::LibertyCell* buffer : *lib->buffers()) {
725-
odb::dbMaster* master = db_->findMaster(buffer->name());
726-
for (odb::dbMTerm* mterm : master->getMTerms()) {
727-
if (mterm->getIoType() == odb::dbIoType::INPUT
728-
&& mterm->getSigType() == odb::dbSigType::CLOCK
729-
&& isClockCellCandidate(buffer)) {
730-
// input port with LEF USE as "CLOCK"
731-
selected_buffers.emplace_back(buffer);
732-
debugPrint(logger_,
733-
CTS,
734-
"buffering",
735-
1,
736-
"{} has input port {} with LEF USE as CLOCK",
737-
buffer->name(),
738-
mterm->getName());
739-
}
740-
}
741-
}
742-
}
743-
delete lib_iter;
744-
}
745-
746-
// third, look for all buffers with name CLKBUF or clkbuf
747-
if (selected_buffers.empty()) {
748-
sta::PatternMatch patternClkBuf(".*CLKBUF.*",
749-
/* is_regexp */ true,
750-
/* nocase */ true,
751-
/* Tcl_interp* */ nullptr);
752-
sta::LibertyLibraryIterator* lib_iter = network_->libertyLibraryIterator();
753-
while (lib_iter->hasNext()) {
754-
sta::LibertyLibrary* lib = lib_iter->next();
755-
if (options_->isCtsLibrarySet()
756-
&& strcmp(lib->name(), options_->getCtsLibrary()) != 0) {
757-
continue;
758-
}
759-
for (sta::LibertyCell* buffer :
760-
lib->findLibertyCellsMatching(&patternClkBuf)) {
761-
if (buffer->isBuffer() && isClockCellCandidate(buffer)) {
762-
debugPrint(logger_,
763-
CTS,
764-
"buffering",
765-
1,
766-
"{} found by 'CLKBUF' pattern match",
767-
buffer->name());
768-
selected_buffers.emplace_back(buffer);
769-
}
770-
}
771-
}
772-
delete lib_iter;
773-
}
774-
775-
// fourth, look for all buffers with name BUF or buf
776-
if (selected_buffers.empty()) {
777-
sta::PatternMatch patternBuf(".*BUF.*",
778-
/* is_regexp */ true,
779-
/* nocase */ true,
780-
/* Tcl_interp* */ nullptr);
781-
lib_iter = network_->libertyLibraryIterator();
782-
while (lib_iter->hasNext()) {
783-
sta::LibertyLibrary* lib = lib_iter->next();
784-
if (options_->isCtsLibrarySet()
785-
&& strcmp(lib->name(), options_->getCtsLibrary()) != 0) {
786-
continue;
787-
}
788-
for (sta::LibertyCell* buffer :
789-
lib->findLibertyCellsMatching(&patternBuf)) {
790-
if (buffer->isBuffer() && isClockCellCandidate(buffer)) {
791-
debugPrint(logger_,
792-
CTS,
793-
"buffering",
794-
1,
795-
"{} found by 'BUF' pattern match",
796-
buffer->name());
797-
selected_buffers.emplace_back(buffer);
798-
}
799-
}
800-
}
801-
delete lib_iter;
802-
}
803-
804-
// abandon attributes & name patterns, just look for all buffers
805-
if (selected_buffers.empty()) {
806-
debugPrint(logger_,
807-
CTS,
808-
"buffering",
809-
1,
810-
"No buffers with clock atributes or name patterns found, using "
811-
"all buffers");
812-
lib_iter = network_->libertyLibraryIterator();
813-
while (lib_iter->hasNext()) {
814-
sta::LibertyLibrary* lib = lib_iter->next();
815-
if (options_->isCtsLibrarySet()
816-
&& strcmp(lib->name(), options_->getCtsLibrary()) != 0) {
817-
continue;
818-
}
819-
for (sta::LibertyCell* buffer : *lib->buffers()) {
820-
if (isClockCellCandidate(buffer)) {
821-
selected_buffers.emplace_back(buffer);
822-
}
823-
}
824-
}
825-
delete lib_iter;
826-
827-
if (selected_buffers.empty()) {
828-
logger_->error(
829-
CTS,
830-
110,
831-
"No clock buffer candidates could be found from any libraries.");
832-
}
833-
}
834-
835-
resizer_->setClockBuffersList(selected_buffers);
836-
837-
for (sta::LibertyCell* buffer : selected_buffers) {
838-
buffers.emplace_back(buffer->name());
839-
debugPrint(logger_,
840-
CTS,
841-
"buffering",
842-
1,
843-
"{} has been inferred as clock buffer",
844-
buffer->name());
845-
}
846-
847-
options_->setBufferListInferred(true);
848-
}
849-
850690
std::string toLowerCase(std::string str)
851691
{
852692
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
@@ -855,12 +695,6 @@ std::string toLowerCase(std::string str)
855695
return str;
856696
}
857697

858-
bool TritonCTS::isClockCellCandidate(sta::LibertyCell* cell)
859-
{
860-
return (!cell->dontUse() && !resizer_->dontUse(cell) && !cell->alwaysOn()
861-
&& !cell->isIsolationCell() && !cell->isLevelShifter());
862-
}
863-
864698
std::string TritonCTS::getRootBufferToString()
865699
{
866700
std::ostringstream buffer_names;
@@ -2557,7 +2391,7 @@ void TritonCTS::findCandidateDummyCells(
25572391
while (lib_iter->hasNext()) {
25582392
sta::LibertyLibrary* lib = lib_iter->next();
25592393
for (sta::LibertyCell* inv : *lib->inverters()) {
2560-
if (inv->isClockCell() && isClockCellCandidate(inv)) {
2394+
if (inv->isClockCell() && resizer_->isClockCellCandidate(inv)) {
25612395
inverters.emplace_back(inv);
25622396
dummyCandidates.emplace_back(inv);
25632397
}
@@ -2576,7 +2410,7 @@ void TritonCTS::findCandidateDummyCells(
25762410
sta::LibertyLibrary* lib = lib_iter->next();
25772411
for (sta::LibertyCell* inv :
25782412
lib->findLibertyCellsMatching(&patternClkInv)) {
2579-
if (inv->isInverter() && isClockCellCandidate(inv)) {
2413+
if (inv->isInverter() && resizer_->isClockCellCandidate(inv)) {
25802414
inverters.emplace_back(inv);
25812415
dummyCandidates.emplace_back(inv);
25822416
}
@@ -2595,7 +2429,7 @@ void TritonCTS::findCandidateDummyCells(
25952429
while (lib_iter->hasNext()) {
25962430
sta::LibertyLibrary* lib = lib_iter->next();
25972431
for (sta::LibertyCell* inv : lib->findLibertyCellsMatching(&patternInv)) {
2598-
if (inv->isInverter() && isClockCellCandidate(inv)) {
2432+
if (inv->isInverter() && resizer_->isClockCellCandidate(inv)) {
25992433
inverters.emplace_back(inv);
26002434
dummyCandidates.emplace_back(inv);
26012435
}
@@ -2610,7 +2444,7 @@ void TritonCTS::findCandidateDummyCells(
26102444
while (lib_iter->hasNext()) {
26112445
sta::LibertyLibrary* lib = lib_iter->next();
26122446
for (sta::LibertyCell* inv : *lib->inverters()) {
2613-
if (isClockCellCandidate(inv)) {
2447+
if (resizer_->isClockCellCandidate(inv)) {
26142448
inverters.emplace_back(inv);
26152449
dummyCandidates.emplace_back(inv);
26162450
}

src/cts/test/check_buffer_inference1.ok

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
[INFO ODB-0130] Created 1 pins.
44
[INFO ODB-0131] Created 288 components and 1728 component-terminals.
55
[INFO ODB-0133] Created 1 nets and 288 connections.
6-
[DEBUG CTS-buffering] CLKBUF_X1 has clock cell attribute
7-
[DEBUG CTS-buffering] CLKBUF_X2 has clock cell attribute
8-
[DEBUG CTS-buffering] CLKBUF_X3 has clock cell attribute
9-
[DEBUG CTS-buffering] CLKBUF_X1 has been inferred as clock buffer
10-
[DEBUG CTS-buffering] CLKBUF_X2 has been inferred as clock buffer
11-
[DEBUG CTS-buffering] CLKBUF_X3 has been inferred as clock buffer
6+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 has clock cell attribute
7+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 has clock cell attribute
8+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 has clock cell attribute
9+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 has been inferred as clock buffer
10+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 has been inferred as clock buffer
11+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 has been inferred as clock buffer
1212
[DEBUG CTS-buffering] CLKBUF_X1 has cap limit:6.0729997e-16 vs. total cap:0, derate:0.01
1313
[DEBUG CTS-buffering] CLKBUF_X2 has cap limit:1.2145999e-15 vs. total cap:0, derate:0.01
1414
[DEBUG CTS-buffering] CLKBUF_X3 has cap limit:1.81885e-15 vs. total cap:0, derate:0.01

src/cts/test/check_buffer_inference1.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ read_def check_buffers.def
1010
create_clock -period 5 clk
1111
set_wire_rc -clock -layer metal5
1212

13+
set_debug RSZ "inferClockBufferList" 1
1314
set_debug CTS "buffering" 1
1415

1516
set_cts_config -wire_unit 20 \

src/cts/test/check_buffer_inference2.ok

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
[INFO ODB-0130] Created 1 pins.
44
[INFO ODB-0131] Created 288 components and 1728 component-terminals.
55
[INFO ODB-0133] Created 1 nets and 288 connections.
6-
[DEBUG CTS-buffering] CLKBUF_X1 has input port A with LEF USE as CLOCK
7-
[DEBUG CTS-buffering] CLKBUF_X2 has input port A with LEF USE as CLOCK
8-
[DEBUG CTS-buffering] CLKBUF_X3 has input port A with LEF USE as CLOCK
9-
[DEBUG CTS-buffering] CLKBUF_X1 has been inferred as clock buffer
10-
[DEBUG CTS-buffering] CLKBUF_X2 has been inferred as clock buffer
11-
[DEBUG CTS-buffering] CLKBUF_X3 has been inferred as clock buffer
6+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 has input port A with LEF USE as CLOCK
7+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 has input port A with LEF USE as CLOCK
8+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 has input port A with LEF USE as CLOCK
9+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 has been inferred as clock buffer
10+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 has been inferred as clock buffer
11+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 has been inferred as clock buffer
1212
[DEBUG CTS-buffering] CLKBUF_X1 has cap limit:6.0729997e-16 vs. total cap:0, derate:0.01
1313
[DEBUG CTS-buffering] CLKBUF_X2 has cap limit:1.2145999e-15 vs. total cap:0, derate:0.01
1414
[DEBUG CTS-buffering] CLKBUF_X3 has cap limit:1.81885e-15 vs. total cap:0, derate:0.01

src/cts/test/check_buffer_inference2.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ read_def check_buffers.def
1010
create_clock -period 5 clk
1111
set_wire_rc -clock -layer metal5
1212

13+
set_debug RSZ "inferClockBufferList" 1
1314
set_debug CTS "buffering" 1
1415

1516
set_cts_config -wire_unit 20 \

src/cts/test/check_buffer_inference3.ok

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
[INFO ODB-0130] Created 1 pins.
44
[INFO ODB-0131] Created 288 components and 1728 component-terminals.
55
[INFO ODB-0133] Created 1 nets and 288 connections.
6-
[DEBUG CTS-buffering] CLKBUF_X1 found by 'CLKBUF' pattern match
7-
[DEBUG CTS-buffering] CLKBUF_X2 found by 'CLKBUF' pattern match
8-
[DEBUG CTS-buffering] CLKBUF_X3 found by 'CLKBUF' pattern match
9-
[DEBUG CTS-buffering] CLKBUF_X1 has been inferred as clock buffer
10-
[DEBUG CTS-buffering] CLKBUF_X2 has been inferred as clock buffer
11-
[DEBUG CTS-buffering] CLKBUF_X3 has been inferred as clock buffer
6+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 found by 'CLKBUF' pattern match
7+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 found by 'CLKBUF' pattern match
8+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 found by 'CLKBUF' pattern match
9+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X1 has been inferred as clock buffer
10+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X2 has been inferred as clock buffer
11+
[DEBUG RSZ-inferClockBufferList] CLKBUF_X3 has been inferred as clock buffer
1212
[DEBUG CTS-buffering] CLKBUF_X1 has cap limit:6.0729997e-16 vs. total cap:0, derate:0.01
1313
[DEBUG CTS-buffering] CLKBUF_X2 has cap limit:1.2145999e-15 vs. total cap:0, derate:0.01
1414
[DEBUG CTS-buffering] CLKBUF_X3 has cap limit:1.81885e-15 vs. total cap:0, derate:0.01

src/cts/test/check_buffer_inference3.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ read_def check_buffers.def
99
create_clock -period 5 clk
1010
set_wire_rc -clock -layer metal5
1111

12+
set_debug RSZ "inferClockBufferList" 1
1213
set_debug CTS "buffering" 1
1314

1415
set_cts_config -wire_unit 20 \

src/rsz/include/rsz/Resizer.hh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ class Resizer : public dbStaState, public dbNetworkObserver
376376
{
377377
clk_buffers_ = clk_buffers;
378378
}
379+
void inferClockBufferList(const char* lib_name,
380+
std::vector<std::string>& buffers);
381+
bool isClockCellCandidate(sta::LibertyCell* cell);
379382
// Clone inverters next to the registers they drive to remove them
380383
// from the clock network.
381384
// yosys is too stupid to use the inverted clock registers

0 commit comments

Comments
 (0)