Skip to content

Commit e1a95da

Browse files
authored
Merge pull request #7539 from mguthaus/slew_checking
rsz: Add slew violation check to size_down, re-enable size_down.
2 parents 83ff256 + cde90b6 commit e1a95da

17 files changed

+733
-403
lines changed

src/rsz/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ the design area is `-max_utilization util` percent of the core area. `util`
55
is between 0 and 100. The `resizer` stops and reports an error if the max
66
utilization is exceeded.
77

8-
98
## Commands
109

1110
```{note}
@@ -79,7 +78,7 @@ The `buffer_ports -inputs` command adds a buffer between the input and its
7978
loads. The `buffer_ports -outputs` adds a buffer between the port driver
8079
and the output port. Inserting buffers on input and output ports makes
8180
the block input capacitances and output drives independent of the block
82-
internals. It uses the buffer library cell defined by `-buffer_cell` if it is given.
81+
internals. It uses the buffer library cell defined by `-buffer_cell` if it is given.
8382

8483
```tcl
8584
buffer_ports
@@ -479,6 +478,7 @@ cell footprint and leakage are also reported.
479478
report_buffers
480479
[-filtered]
481480
```
481+
482482
#### Options
483483

484484
| Switch Name | Description |

src/rsz/src/BaseMove.cc

Lines changed: 186 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@
1717
#include "rsz/Resizer.hh"
1818
#include "sta/ArcDelayCalc.hh"
1919
#include "sta/Delay.hh"
20+
#include "sta/Fuzzy.hh"
2021
#include "sta/Graph.hh"
22+
#include "sta/GraphDelayCalc.hh"
2123
#include "sta/Liberty.hh"
2224
#include "sta/MinMax.hh"
2325
#include "sta/NetworkClass.hh"
26+
#include "sta/PortDirection.hh"
2427
#include "sta/TimingArc.hh"
2528
#include "sta/Transition.hh"
2629
#include "sta/Vector.hh"
2730
#include "utl/Logger.h"
2831

2932
namespace rsz {
30-
3133
using std::max;
3234
using std::string;
3335
using std::vector;
@@ -403,8 +405,8 @@ Instance* BaseMove::makeBuffer(LibertyCell* cell,
403405
// Acceptance criteria are as follows:
404406
// For direct fanout paths (fanout paths of drvr_pin), accept buffer removal
405407
// if slack improves (may still be violating)
406-
// For side fanout paths (fanout paths of side_out_pin*), accept buffer removal
407-
// if slack doesn't become violating (no new violations)
408+
// For side fanout paths (fanout paths of side_out_pin*), accept buffer
409+
// removal if slack doesn't become violating (no new violations)
408410
//
409411
// input_net output_net
410412
// prev_drv_pin ------> (drvr_input_pin drvr_pin) ------>
@@ -699,21 +701,198 @@ bool BaseMove::replaceCell(Instance* inst, const LibertyCell* replacement)
699701
}
700702
return false;
701703
}
704+
Slack BaseMove::getWorstInputSlack(Instance* inst)
705+
{
706+
Slack worst_slack = INF;
707+
auto pin_iter
708+
= std::unique_ptr<InstancePinIterator>(network_->pinIterator(inst));
709+
while (pin_iter->hasNext()) {
710+
const Pin* pin = pin_iter->next();
711+
if (network_->direction(pin)->isInput()) {
712+
Vertex* vertex = graph_->pinDrvrVertex(pin);
713+
if (vertex) {
714+
worst_slack
715+
= std::min(worst_slack, sta_->vertexSlack(vertex, resizer_->max_));
716+
}
717+
}
718+
}
719+
return worst_slack;
720+
}
721+
722+
Slack BaseMove::getWorstOutputSlack(Instance* inst)
723+
{
724+
Slack worst_slack = INF;
725+
726+
// Iterate through all pins of the instance to find output pins
727+
auto pin_iter
728+
= std::unique_ptr<InstancePinIterator>(network_->pinIterator(inst));
729+
while (pin_iter->hasNext()) {
730+
const Pin* inst_pin = pin_iter->next();
731+
if (network_->direction(inst_pin)->isOutput()) {
732+
Vertex* vertex = graph_->pinLoadVertex(inst_pin);
733+
if (vertex) {
734+
worst_slack
735+
= std::min(worst_slack, sta_->vertexSlack(vertex, resizer_->max_));
736+
}
737+
}
738+
}
739+
return worst_slack;
740+
}
741+
742+
ArcDelay BaseMove::getWorstIntrinsicDelay(const LibertyPort* input_port)
743+
{
744+
const LibertyCell* cell = input_port->libertyCell();
745+
vector<const LibertyPort*> output_ports = getOutputPorts(cell);
746+
747+
// Just return the worst of all the outputs, if there's more than one
748+
ArcDelay worst_intrinsic_delay = -INF;
749+
for (const LibertyPort* output_port : output_ports) {
750+
if (output_port->direction()->isOutput()) {
751+
worst_intrinsic_delay
752+
= max(worst_intrinsic_delay, output_port->intrinsicDelay(nullptr));
753+
}
754+
}
755+
return worst_intrinsic_delay;
756+
}
757+
758+
vector<const LibertyPort*> BaseMove::getOutputPorts(const LibertyCell* cell)
759+
{
760+
vector<const LibertyPort*> fanouts;
761+
762+
sta::LibertyCellPortIterator port_iter(cell);
763+
while (port_iter.hasNext()) {
764+
const LibertyPort* port = port_iter.next();
765+
if (port->direction()->isOutput()) {
766+
fanouts.push_back(port);
767+
}
768+
}
769+
770+
return fanouts;
771+
}
702772

703-
vector<const Pin*> BaseMove::getFanouts(const Instance* inst)
773+
vector<const Pin*> BaseMove::getOutputPins(const Instance* inst)
704774
{
705-
vector<const Pin*> fanouts;
775+
vector<const Pin*> outputs;
706776

707777
auto pin_iter
708778
= std::unique_ptr<InstancePinIterator>(network_->pinIterator(inst));
709779
while (pin_iter->hasNext()) {
710780
const Pin* pin = pin_iter->next();
711781
if (network_->direction(pin)->isOutput()) {
712-
fanouts.push_back(pin);
782+
outputs.push_back(pin);
713783
}
714784
}
715785

716-
return fanouts;
786+
return outputs;
787+
}
788+
789+
bool BaseMove::checkMaxCapViolation(const Pin* output_pin,
790+
LibertyPort* output_port,
791+
float output_cap)
792+
{
793+
float max_cap;
794+
bool cap_limit_exists;
795+
// FIXME: Can we update to consider multiple corners?
796+
output_port->capacitanceLimit(resizer_->max_, max_cap, cap_limit_exists);
797+
798+
debugPrint(logger_,
799+
RSZ,
800+
"opt_moves",
801+
3,
802+
" fanout pin {} cap {} output_cap {} ",
803+
output_port->name(),
804+
max_cap,
805+
output_cap);
806+
807+
if (cap_limit_exists && max_cap > 0.0 && output_cap > max_cap) {
808+
debugPrint(logger_,
809+
RSZ,
810+
"opt_moves",
811+
2,
812+
" skip based on max cap {} gate={} cap={} max_cap={}",
813+
network_->pathName(output_pin),
814+
output_port->libertyCell()->name(),
815+
output_cap,
816+
max_cap);
817+
return true;
818+
}
819+
820+
return false;
821+
}
822+
823+
bool BaseMove::checkMaxSlewViolation(const Pin* output_pin,
824+
LibertyPort* output_port,
825+
float output_slew_factor,
826+
float output_cap,
827+
const DcalcAnalysisPt* dcalc_ap)
828+
{
829+
float output_res = output_port->driveResistance();
830+
float output_slew = output_slew_factor * output_res * output_cap;
831+
float max_slew;
832+
bool slew_limit_exists;
833+
834+
sta_->findSlewLimit(output_port,
835+
dcalc_ap->corner(),
836+
resizer_->max_,
837+
max_slew,
838+
slew_limit_exists);
839+
840+
if (output_slew > max_slew) {
841+
debugPrint(logger_,
842+
RSZ,
843+
"opt_moves",
844+
2,
845+
" skip based on max slew {} gate={} slew={} max_slew={}",
846+
network_->pathName(output_pin),
847+
output_port->libertyCell()->name(),
848+
output_slew,
849+
max_slew);
850+
return true;
851+
}
852+
853+
return false;
854+
}
855+
856+
float BaseMove::computeElmoreSlewFactor(const Pin* output_pin,
857+
LibertyPort* output_port,
858+
float output_load_cap)
859+
{
860+
float elmore_slew_factor = 0.0;
861+
862+
// Get the vertex for the output pin
863+
Vertex* output_vertex = graph_->pinDrvrVertex(output_pin);
864+
865+
// Get the output slew
866+
const Slew output_slew = sta_->vertexSlew(output_vertex, resizer_->max_);
867+
868+
// Get the output resistance
869+
float output_res = output_port->driveResistance();
870+
871+
// Can have gates without fanout (e.g. QN of flop) which have no load
872+
if (output_res > 0.0 && output_load_cap > 0.0) {
873+
elmore_slew_factor = output_slew / (output_res * output_load_cap);
874+
}
875+
876+
return elmore_slew_factor;
717877
}
718878

879+
////////////////////////////////////////////////////////////////
880+
881+
LibertyCellSeq BaseMove::getSwappableCells(LibertyCell* base)
882+
{
883+
LibertyCellSeq buffer_sizes;
884+
if (base->isBuffer()) {
885+
for (LibertyCell* buffer : resizer_->buffer_fast_sizes_) {
886+
buffer_sizes.push_back(buffer);
887+
}
888+
if (resizer_->buffer_fast_sizes_.count(base) == 0) {
889+
return LibertyCellSeq();
890+
}
891+
return buffer_sizes;
892+
}
893+
return resizer_->getSwappableCells(base);
894+
}
895+
896+
////////////////////////////////////////////////////////////////
897+
// namespace rsz
719898
} // namespace rsz

src/rsz/src/BaseMove.hh

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class EstimateParasitics;
4646

4747
namespace rsz {
4848

49+
using std::vector;
50+
4951
using odb::dbMaster;
5052

5153
using odb::dbMaster;
@@ -226,12 +228,29 @@ class BaseMove : public sta::dbStaState
226228
const DcalcAnalysisPt* dcalc_ap);
227229
bool replaceCell(Instance* inst, const LibertyCell* replacement);
228230

231+
bool checkMaxCapViolation(const Pin* output_pin,
232+
LibertyPort* output_port,
233+
float output_cap);
234+
bool checkMaxSlewViolation(const Pin* output_pin,
235+
LibertyPort* output_port,
236+
float output_slew_factor,
237+
float output_cap,
238+
const DcalcAnalysisPt* dcalc_ap);
239+
float computeElmoreSlewFactor(const Pin* output_pin,
240+
LibertyPort* output_port,
241+
float output_load_cap);
242+
ArcDelay getWorstIntrinsicDelay(const LibertyPort* input_port);
243+
Slack getWorstInputSlack(Instance* inst);
244+
Slack getWorstOutputSlack(Instance* inst);
245+
vector<const LibertyPort*> getOutputPorts(const LibertyCell* cell);
246+
vector<const Pin*> getOutputPins(const Instance* inst);
247+
LibertyCellSeq getSwappableCells(LibertyCell* base);
248+
249+
static constexpr int size_down_max_fanout_ = 10;
229250
static constexpr int rebuffer_max_fanout_ = 20;
230251
static constexpr int split_load_min_fanout_ = 8;
231252
static constexpr int buffer_removal_max_fanout_ = 10;
232253
static constexpr float rebuffer_relaxation_factor_ = 0.03;
233-
234-
std::vector<const Pin*> getFanouts(const Instance* inst);
235254
};
236255

237256
} // namespace rsz

src/rsz/src/CloneMove.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@
2626

2727
namespace rsz {
2828

29+
using odb::Point;
2930
using std::pair;
3031
using std::string;
3132
using std::vector;
3233

33-
using odb::Point;
34-
3534
using utl::RSZ;
3635

3736
using sta::dbITerm;

src/rsz/src/RepairSetup.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
127127
}
128128
break;
129129
case MoveType::SIZE:
130+
move_sequence.push_back(resizer_->size_up_move_.get());
130131
if (!skip_size_down) {
131132
move_sequence.push_back(resizer_->size_down_move_.get());
132133
}
133-
move_sequence.push_back(resizer_->size_up_move_.get());
134134
break;
135135
case MoveType::SIZEUP:
136136
move_sequence.push_back(resizer_->size_up_move_.get());
@@ -170,9 +170,12 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
170170
if (!skip_vt_swap && resizer_->lib_data_->sorted_vt_categories.size() > 1) {
171171
move_sequence.push_back(resizer_->vt_swap_speed_move_.get());
172172
}
173-
// TODO: Add size_down_move to the sequence if we want to allow
174173
// Always have sizing
175174
move_sequence.push_back(resizer_->size_up_move_.get());
175+
// Disabled by default for now
176+
if (!skip_size_down) {
177+
// move_sequence.push_back(resizer_->size_down_move_.get());
178+
}
176179
if (!skip_pin_swap) {
177180
move_sequence.push_back(resizer_->swap_pins_move_.get());
178181
}
@@ -189,6 +192,7 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
189192

190193
string repair_moves = "Repair move sequence: ";
191194
for (auto move : move_sequence) {
195+
move->init();
192196
repair_moves += move->name() + string(" ");
193197
}
194198
logger_->info(RSZ, 100, repair_moves);
@@ -249,6 +253,7 @@ bool RepairSetup::repairSetup(const float setup_slack_margin,
249253

250254
// Ensure that max cap and max fanout violations don't get worse
251255
sta_->checkCapacitanceLimitPreamble();
256+
sta_->checkSlewLimitPreamble();
252257
sta_->checkFanoutLimitPreamble();
253258

254259
est::IncrementalParasiticsGuard guard(estimate_parasitics_);

0 commit comments

Comments
 (0)