Skip to content

Commit 3556f9c

Browse files
authored
Merge pull request #8113 from The-OpenROAD-Project-staging/secure-upsize-vt
Add VT swap and sizeup match transforms to setup fixing
2 parents d30c522 + 86e520b commit 3556f9c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1343
-875
lines changed

src/rsz/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ cc_library(
4848
"src/SwapPinsMove.hh",
4949
"src/UnbufferMove.cc",
5050
"src/UnbufferMove.hh",
51+
"src/VTSwapMove.hh",
52+
"src/VTSwapMove.cc",
5153
],
5254
hdrs = [
5355
"include/rsz/MakeResizer.hh",

src/rsz/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ repair_timing
226226
[-skip_buffering]
227227
[-skip_buffer_removal]
228228
[-skip_last_gasp]
229+
[-skip_vt_swap]
229230
[-repair_tns tns_end_percent]
230231
[-max_passes passes]
231232
[-max_repairs_per_pass max_repairs_per_pass]
@@ -252,6 +253,7 @@ repair_timing
252253
| `-skip_buffering` | Flag to skip rebuffering and load splitting. The default is to perform rebuffering and load splitting transforms during setup fixing. |
253254
| `-skip_buffer_removal` | Flag to skip buffer removal. The default is to perform buffer removal transform during setup fixing. |
254255
| `-skip_last_gasp` | Flag to skip final ("last gasp") optimizations. The default is to perform greedy sizing at the end of optimization. |
256+
| `-skip_vt_swap` | Flag to skip threshold voltage (VT) swap optimizations. The default is to perform VT swap optimization to improve timing QoR. |
255257
| `-repair_tns` | Percentage of violating endpoints to repair (0-100). When `tns_end_percent` is zero, only the worst endpoint is repaired. When `tns_end_percent` is 100 (default), all violating endpoints are repaired. |
256258
| `-max_repairs_per_pass` | Maximum repairs per pass, default is 1. On the worst paths, the maximum number of repairs is attempted. It gradually decreases until the final violations which only get 1 repair per pass. |
257259
| `-max_utilization` | Defines the percentage of core area used. |
@@ -449,6 +451,7 @@ The `report_equiv_cells` command finds all functionally equivalent library cells
449451
report_equiv_cells
450452
[-match_cell_footprint]
451453
[-all]
454+
[-vt]
452455
lib_cell
453456
```
454457

@@ -458,6 +461,7 @@ report_equiv_cells
458461
| ----- | ----- |
459462
| `-match_cell_footprint` | Limit equivalent cell list to include only cells that match library cell_footprint attribute. |
460463
| `-all` | List all equivalent cells, ignoring sizing restrictions and cell_footprint. Cells excluded due to these restrictions are marked with an asterisk. |
464+
| `-vt` | List all threshold voltage (VT) equivalent cells such as HVT, RVT, LVT, SLVT. |
461465

462466
### Reporting Buffers
463467

src/rsz/include/rsz/Resizer.hh

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class SizeDownMove;
118118
class SizeUpMove;
119119
class SwapPinsMove;
120120
class UnbufferMove;
121+
class VTSwapSpeedMove;
122+
class SizeUpMatchMove;
121123
class RegisterOdbCallbackGuard;
122124

123125
class NetHash
@@ -138,7 +140,9 @@ enum class MoveType
138140
SIZEUP,
139141
SIZEDOWN,
140142
CLONE,
141-
SPLIT
143+
SPLIT,
144+
VTSWAP_SPEED, // VT swap for timing (need VT swap for power also)
145+
SIZEUP_MATCH // sizeup to match drive strength vs. prev stage
142146
};
143147

144148
// Voltage Threshold (VT) category identifier
@@ -155,6 +159,11 @@ struct VTCategory
155159
}
156160
return vt_name < other.vt_name;
157161
}
162+
bool operator==(const VTCategory& other) const
163+
{
164+
return (vt_index == other.vt_index && vt_name == other.vt_name);
165+
}
166+
bool operator!=(const VTCategory& other) const { return !(*this == other); }
158167
};
159168

160169
// Leakage statistics for cells in a single VT category
@@ -278,7 +287,8 @@ class Resizer : public dbStaState, public dbNetworkObserver
278287
bool skip_size_down,
279288
bool skip_buffering,
280289
bool skip_buffer_removal,
281-
bool skip_last_gasp);
290+
bool skip_last_gasp,
291+
bool skip_vt_swap);
282292
// For testing.
283293
void repairSetup(const Pin* end_pin);
284294
// For testing.
@@ -407,7 +417,7 @@ class Resizer : public dbStaState, public dbNetworkObserver
407417
double dbuToMeters(int dist) const;
408418
int metersToDbu(double dist) const;
409419
void makeEquivCells();
410-
std::pair<int, std::string> cellVTType(dbMaster* master);
420+
VTCategory cellVTType(dbMaster* master);
411421

412422
////////////////////////////////////////////////////////////////
413423
void initBlock();
@@ -419,10 +429,10 @@ class Resizer : public dbStaState, public dbNetworkObserver
419429
// For debugging - calls getSwappableCells
420430
void reportEquivalentCells(LibertyCell* base_cell,
421431
bool match_cell_footprint,
422-
bool report_all_cells);
432+
bool report_all_cells,
433+
bool report_vt_equiv);
423434
void reportBuffers(bool filtered);
424-
void getBufferList(LibertyCellSeq& buffer_list,
425-
LibraryAnalysisData& lib_data);
435+
void getBufferList(LibertyCellSeq& buffer_list);
426436
void setDebugGraphics(std::shared_ptr<ResizerObserver> graphics);
427437

428438
static MoveType parseMove(const std::string& s);
@@ -434,6 +444,9 @@ class Resizer : public dbStaState, public dbNetworkObserver
434444
return estimate_parasitics_;
435445
}
436446

447+
// Library analysis data
448+
std::unique_ptr<LibraryAnalysisData> lib_data_;
449+
437450
protected:
438451
void init();
439452
double computeDesignArea();
@@ -495,6 +508,7 @@ class Resizer : public dbStaState, public dbNetworkObserver
495508

496509
void resizePreamble();
497510
LibertyCellSeq getSwappableCells(LibertyCell* source_cell);
511+
LibertyCellSeq getVTEquivCells(LibertyCell* source_cell);
498512

499513
bool getCin(const LibertyCell* cell, float& cin);
500514
// Resize drvr_pin instance to target slew.
@@ -717,6 +731,12 @@ class Resizer : public dbStaState, public dbNetworkObserver
717731

718732
// Cache results of getSwappableCells() as this is expensive for large PDKs.
719733
std::unordered_map<LibertyCell*, LibertyCellSeq> swappable_cells_cache_;
734+
// Cache VT equivalent cells for each cell, equivalent cells are sorted in
735+
// increasing order of leakage
736+
// BUF_X1_RVT : { BUF_X1_RVT, BUF_X1_LVT, BUF_X1_SLVT }
737+
// BUF_X1_LVT : { BUF_X1_RVT, BUF_X1_LVT, BUF_X1_SLVT }
738+
// ...
739+
std::unordered_map<LibertyCell*, LibertyCellSeq> vt_equiv_cells_cache_;
720740

721741
std::unique_ptr<CellTargetLoadMap> target_load_map_;
722742
VertexSeq level_drvr_vertices_;
@@ -774,7 +794,7 @@ class Resizer : public dbStaState, public dbNetworkObserver
774794
double buffer_sizing_cap_ratio_;
775795

776796
// VT layer hash
777-
std::unordered_map<dbMaster*, std::pair<int, std::string>> vt_map_;
797+
std::unordered_map<dbMaster*, VTCategory> vt_map_;
778798
std::unordered_map<size_t, int>
779799
vt_hash_map_; // maps hash value to unique int
780800

@@ -789,6 +809,8 @@ class Resizer : public dbStaState, public dbNetworkObserver
789809
std::unique_ptr<SizeUpMove> size_up_move_;
790810
std::unique_ptr<SwapPinsMove> swap_pins_move_;
791811
std::unique_ptr<UnbufferMove> unbuffer_move_;
812+
std::unique_ptr<VTSwapSpeedMove> vt_swap_speed_move_;
813+
std::unique_ptr<SizeUpMatchMove> size_up_match_move_;
792814
int accepted_move_count_ = 0;
793815
int rejected_move_count_ = 0;
794816

@@ -807,6 +829,8 @@ class Resizer : public dbStaState, public dbNetworkObserver
807829
friend class CloneMove;
808830
friend class SwapPinsMove;
809831
friend class UnbufferMove;
832+
friend class SizeUpMatchMove;
833+
friend class VTSwapSpeedMove;
810834
friend class SwapArithModules;
811835
friend class ConcreteSwapArithModules;
812836
friend class Rebuffer;

src/rsz/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_library(rsz_lib
2626
SplitLoadMove.cc
2727
SwapPinsMove.cc
2828
UnbufferMove.cc
29+
VTSwapMove.cc
2930
Resizer.cc
3031
OdbCallBack.cc
3132
ConcreteSwapArithModules.cc

src/rsz/src/RepairHold.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,21 +212,20 @@ bool isDelayCell(const std::string& cell_name)
212212
void RepairHold::filterHoldBuffers(LibertyCellSeq& hold_buffers)
213213
{
214214
LibertyCellSeq buffer_list;
215-
LibraryAnalysisData lib_data;
216-
resizer_->getBufferList(buffer_list, lib_data);
215+
resizer_->getBufferList(buffer_list);
217216

218217
// Pick the least leaky VT for multiple VTs
219218
int best_vt_index = -1;
220-
int num_vt = lib_data.sorted_vt_categories.size();
219+
int num_vt = resizer_->lib_data_->sorted_vt_categories.size();
221220
if (num_vt > 0) {
222-
best_vt_index = lib_data.sorted_vt_categories[0].first.vt_index;
221+
best_vt_index = resizer_->lib_data_->sorted_vt_categories[0].first.vt_index;
223222
}
224223

225224
// Pick the shortest cell site because this offers the most flexibility for
226225
// hold fixing
227226
int best_height = std::numeric_limits<int>::max();
228227
odb::dbSite* best_site = nullptr;
229-
for (const auto& site_data : lib_data.cells_by_site) {
228+
for (const auto& site_data : resizer_->lib_data_->cells_by_site) {
230229
int height = site_data.first->getHeight();
231230
if (height < best_height) {
232231
best_height = height;
@@ -236,7 +235,7 @@ void RepairHold::filterHoldBuffers(LibertyCellSeq& hold_buffers)
236235

237236
// Use DELAY cell footprint if available
238237
bool lib_has_footprints = false;
239-
for (const auto& [ft_str, count] : lib_data.cells_by_footprint) {
238+
for (const auto& [ft_str, count] : resizer_->lib_data_->cells_by_footprint) {
240239
if (isDelayCell(ft_str)) {
241240
lib_has_footprints = true;
242241
break;
@@ -313,7 +312,7 @@ bool RepairHold::addMatchingBuffers(const LibertyCellSeq& buffer_list,
313312
bool vt_matches = true;
314313
if (match_vt) {
315314
auto vt_type = resizer_->cellVTType(master);
316-
vt_matches = best_vt_index == -1 || vt_type.first == best_vt_index;
315+
vt_matches = best_vt_index == -1 || vt_type.vt_index == best_vt_index;
317316
}
318317

319318
bool footprint_matches = true;

src/rsz/src/RepairSetup.cc

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#include "CloneMove.hh"
1818
#include "Rebuffer.hh"
1919
#include "SizeDownMove.hh"
20+
// This includes SizeUpMatchMove
2021
#include "SizeUpMove.hh"
2122
#include "SplitLoadMove.hh"
2223
#include "SwapPinsMove.hh"
2324
#include "UnbufferMove.hh"
25+
#include "VTSwapMove.hh"
2426
#include "rsz/Resizer.hh"
2527
#include "sta/Corner.hh"
2628
#include "sta/DcalcAnalysisPt.hh"
@@ -86,7 +88,8 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
8688
const bool skip_size_down,
8789
const bool skip_buffering,
8890
const bool skip_buffer_removal,
89-
const bool skip_last_gasp)
91+
const bool skip_last_gasp,
92+
const bool skip_vt_swap)
9093
{
9194
bool repaired = false;
9295
init();
@@ -140,6 +143,15 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
140143
move_sequence.push_back(resizer_->split_load_move_.get());
141144
}
142145
break;
146+
case MoveType::VTSWAP_SPEED:
147+
if (!skip_vt_swap
148+
&& resizer_->lib_data_->sorted_vt_categories.size() > 1) {
149+
move_sequence.push_back(resizer_->vt_swap_speed_move_.get());
150+
}
151+
break;
152+
case MoveType::SIZEUP_MATCH:
153+
move_sequence.push_back(resizer_->size_up_match_move_.get());
154+
break;
143155
}
144156
}
145157

@@ -148,6 +160,9 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
148160
if (!skip_buffer_removal) {
149161
move_sequence.push_back(resizer_->unbuffer_move_.get());
150162
}
163+
if (!skip_vt_swap && resizer_->lib_data_->sorted_vt_categories.size() > 1) {
164+
move_sequence.push_back(resizer_->vt_swap_speed_move_.get());
165+
}
151166
// TODO: Add size_down_move to the sequence if we want to allow
152167
// Always have sizing
153168
move_sequence.push_back(resizer_->size_up_move_.get());
@@ -457,6 +472,8 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
457472
int clone_moves_ = resizer_->clone_move_->numCommittedMoves();
458473
int split_load_moves_ = resizer_->split_load_move_->numCommittedMoves();
459474
int unbuffer_moves_ = resizer_->unbuffer_move_->numCommittedMoves();
475+
int vt_swap_moves_ = resizer_->vt_swap_speed_move_->numCommittedMoves();
476+
int size_up_match_moves_ = resizer_->size_up_match_move_->numCommittedMoves();
460477

461478
if (unbuffer_moves_ > 0) {
462479
repaired = true;
@@ -476,14 +493,18 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
476493
}
477494
logger_->metric("design__instance__count__setup_buffer",
478495
buffer_moves_ + split_load_moves_);
479-
if (size_up_moves_ + size_down_moves_ > 0) {
496+
if (size_up_moves_ + size_down_moves_ + size_up_match_moves_ + vt_swap_moves_
497+
> 0) {
480498
repaired = true;
481499
logger_->info(RSZ,
482500
51,
483-
"Resized {} instances, {} sized up, {} sized down.",
484-
size_up_moves_ + size_down_moves_,
501+
"Resized {} instances: {} up, {} up match, {} down, {} VT",
502+
size_up_moves_ + size_up_match_moves_ + size_down_moves_
503+
+ vt_swap_moves_,
485504
size_up_moves_,
486-
size_down_moves_);
505+
size_up_match_moves_,
506+
size_down_moves_,
507+
vt_swap_moves_);
487508
}
488509
if (swap_pins_moves_ > 0) {
489510
repaired = true;
@@ -517,6 +538,7 @@ void RepairSetup::repairSetup(const Pin* end_pin)
517538

518539
move_sequence.clear();
519540
move_sequence = {resizer_->unbuffer_move_.get(),
541+
resizer_->vt_swap_speed_move_.get(),
520542
resizer_->size_down_move_.get(),
521543
resizer_->size_up_move_.get(),
522544
resizer_->swap_pins_move_.get(),
@@ -755,7 +777,9 @@ void RepairSetup::printProgress(const int iteration,
755777
itr_field,
756778
resizer_->unbuffer_move_->numMoves(),
757779
resizer_->size_up_move_->numMoves()
758-
+ resizer_->size_down_move_->numMoves(),
780+
+ resizer_->size_down_move_->numMoves()
781+
+ resizer_->size_up_match_move_->numMoves()
782+
+ resizer_->vt_swap_speed_move_->numMoves(),
759783
resizer_->buffer_move_->numMoves()
760784
+ resizer_->split_load_move_->numMoves(),
761785
resizer_->clone_move_->numMoves(),
@@ -810,9 +834,14 @@ bool RepairSetup::terminateProgress(const int iteration,
810834

811835
// Perform some last fixing based on sizing only.
812836
// This is a greedy opto that does not degrade WNS or TNS.
813-
// TODO: add VT swap
814837
void RepairSetup::repairSetupLastGasp(const OptoParams& params, int& num_viols)
815838
{
839+
move_sequence.clear();
840+
move_sequence = {resizer_->vt_swap_speed_move_.get(),
841+
resizer_->size_up_match_move_.get(),
842+
resizer_->size_up_move_.get(),
843+
resizer_->swap_pins_move_.get()};
844+
816845
// Sort remaining failing endpoints
817846
const VertexSet* endpoints = sta_->endpoints();
818847
vector<pair<Vertex*, Slack>> violating_ends;
@@ -838,15 +867,6 @@ void RepairSetup::repairSetupLastGasp(const OptoParams& params, int& num_viols)
838867
return;
839868
}
840869

841-
// Don't do anything unless there was some progress from previous fixing
842-
if ((params.initial_tns - curr_tns) / params.initial_tns < 0.05) {
843-
// clang-format off
844-
debugPrint(logger_, RSZ, "repair_setup", 1, "last gasp is bailing out "
845-
"because TNS was reduced by < 5% from previous fixing");
846-
// clang-format on
847-
return;
848-
}
849-
850870
int end_index = 0;
851871
int max_end_count = violating_ends.size();
852872
if (max_end_count == 0) {

src/rsz/src/RepairSetup.hh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ class RepairSetup : public sta::dbStaState
8484
bool skip_size_down,
8585
bool skip_buffering,
8686
bool skip_buffer_removal,
87-
bool skip_last_gasp);
87+
bool skip_last_gasp,
88+
bool skip_vt_swap);
8889
// For testing.
8990
void repairSetup(const Pin* end_pin);
9091
// For testing.

0 commit comments

Comments
 (0)