Skip to content

Commit 1b1487a

Browse files
committed
rsz: Remove borrowed latch effective slack
Remove the effective slack endpoint model now that setup repair expands latch-through paths to include the latch D fanin. Use reported STA endpoint slack again for endpoint collection and repair progress checks to avoid creating artificial latch D endpoint violations. Keep the C++ coverage focused on latch-through target collection and rely on the Tcl regressions for end-to-end borrow reduction. Test: cmake --build build -j32 --target openroad TestResizer Test: ctest --test-dir build -R '^TestResizer\.|rsz\.inferred_clock_gator_time_borrow.*\.tcl' --output-on-failure Test: bazelisk test //src/rsz/test:TestResizer //src/rsz/test:inferred_clock_gator_time_borrow-tcl_test //src/rsz/test:inferred_clock_gator_time_borrow_covered-tcl_test //src/rsz/test:inferred_clock_gator_time_borrow_repair_pin-tcl_test //src/rsz/test:inferred_clock_gator_time_borrow_tns-tcl_test Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
1 parent df2aeb7 commit 1b1487a

5 files changed

Lines changed: 6 additions & 208 deletions

File tree

src/rsz/src/RepairTargetCollector.cc

Lines changed: 3 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "rsz/Resizer.hh"
2424
#include "sta/Delay.hh"
2525
#include "sta/ExceptionPath.hh"
26-
#include "sta/FuncExpr.hh"
2726
#include "sta/Fuzzy.hh"
2827
#include "sta/Graph.hh"
2928
#include "sta/GraphClass.hh"
@@ -39,12 +38,10 @@
3938
#include "sta/Sdc.hh"
4039
#include "sta/Search.hh"
4140
#include "sta/SearchClass.hh"
42-
#include "sta/Sequential.hh"
4341
#include "sta/Sta.hh"
4442
#include "sta/StringUtil.hh"
4543
#include "sta/TimingArc.hh"
4644
#include "sta/Transition.hh"
47-
#include "sta/VisitPathEnds.hh"
4845
#include "utl/Logger.h"
4946

5047
namespace rsz {
@@ -815,9 +812,9 @@ void RepairTargetCollector::collectViolatingEndpoints()
815812

816813
const sta::VertexSet& endpoints = sta_->endpoints();
817814
for (sta::Vertex* endpoint : endpoints) {
818-
const sta::Slack effective_slack = getEndpointEffectiveSlack(endpoint);
819-
if (sta::fuzzyLess(effective_slack, slack_margin_)) {
820-
violating_endpoints_.emplace_back(endpoint->pin(), effective_slack);
815+
const sta::Slack slack = sta_->slack(endpoint, max_);
816+
if (sta::fuzzyLess(slack, slack_margin_)) {
817+
violating_endpoints_.emplace_back(endpoint->pin(), slack);
821818
}
822819
}
823820

@@ -835,144 +832,6 @@ void RepairTargetCollector::collectViolatingEndpoints()
835832
* 100));
836833
}
837834

838-
namespace {
839-
840-
// Track the worst-slack constrained max path end at a vertex and record its
841-
// latch time borrow. Non-latch path ends report zero borrow.
842-
class WorstPathEndBorrowVisitor : public sta::PathEndVisitor
843-
{
844-
public:
845-
WorstPathEndBorrowVisitor(const sta::MinMax* min_max,
846-
const sta::StaState* sta)
847-
: min_max_(min_max), sta_(sta)
848-
{
849-
}
850-
sta::PathEndVisitor* copy() const override
851-
{
852-
return new WorstPathEndBorrowVisitor(*this);
853-
}
854-
void visit(sta::PathEnd* path_end) override
855-
{
856-
if (path_end->isUnconstrained() || path_end->minMax(sta_) != min_max_) {
857-
return;
858-
}
859-
const sta::Slack end_slack = path_end->slack(sta_);
860-
if (sta::delayLess(end_slack, worst_slack_, sta_)) {
861-
worst_slack_ = end_slack;
862-
borrow_ = path_end->borrow(sta_);
863-
}
864-
}
865-
sta::Arrival borrow() const { return borrow_; }
866-
867-
private:
868-
const sta::MinMax* min_max_;
869-
const sta::StaState* sta_;
870-
sta::Slack worst_slack_ = sta::INF;
871-
sta::Arrival borrow_ = 0.0;
872-
};
873-
874-
} // namespace
875-
876-
sta::Slack RepairTargetCollector::getEndpointEffectiveSlack(
877-
sta::Vertex* endpoint) const
878-
{
879-
const sta::Slack reported_slack = sta_->slack(endpoint, max_);
880-
if (sta::fuzzyGreater(reported_slack, slack_margin_)) {
881-
return reported_slack;
882-
}
883-
884-
// Visit the path ends stored at this endpoint and read the time borrow of
885-
// the worst-slack one. This avoids the heavyweight findPathEnds() machinery
886-
// (exception filter, path group construction, sorting) per endpoint.
887-
sta::VisitPathEnds visit_ends(sta_);
888-
WorstPathEndBorrowVisitor borrow_visitor(max_, sta_);
889-
visit_ends.visitPathEnds(endpoint, &borrow_visitor);
890-
891-
const sta::Arrival borrow = borrow_visitor.borrow();
892-
if (sta::fuzzyLessEqual(borrow, 0.0f)) {
893-
return reported_slack;
894-
}
895-
896-
const std::vector<const sta::Pin*> output_pins = latchOutputPins(endpoint);
897-
const sta::Slack output_slack = latchOutputWorstSlack(output_pins);
898-
const sta::Slack uncovered_borrow
899-
= std::max<float>(borrow - std::max<float>(output_slack, 0.0f), 0.0f);
900-
return reported_slack - uncovered_borrow;
901-
}
902-
903-
std::vector<const sta::Pin*> RepairTargetCollector::latchOutputPins(
904-
sta::Vertex* endpoint) const
905-
{
906-
std::vector<const sta::Pin*> output_pins;
907-
const std::function<void(
908-
sta::Instance*, sta::LibertyCell*, sta::LibertyPort*)>
909-
add_output_pin = [this, &output_pins](sta::Instance* inst,
910-
sta::LibertyCell* cell,
911-
sta::LibertyPort* state_port) {
912-
const sta::Pin* output_pin = network_->findPin(inst, state_port);
913-
if (output_pin != nullptr) {
914-
output_pins.push_back(output_pin);
915-
return;
916-
}
917-
918-
// Some libraries declare latch state as an internal port and expose it
919-
// through an output pin function, for example Q = IQ.
920-
sta::LibertyCellPortIterator port_iter(cell);
921-
while (port_iter.hasNext()) {
922-
sta::LibertyPort* port = port_iter.next();
923-
sta::FuncExpr* func = port->function();
924-
if (!port->direction()->isAnyOutput() || func == nullptr
925-
|| !func->hasPort(state_port)) {
926-
continue;
927-
}
928-
929-
output_pin = network_->findPin(inst, port);
930-
if (output_pin != nullptr
931-
&& std::ranges::find(output_pins, output_pin)
932-
== output_pins.end()) {
933-
output_pins.push_back(output_pin);
934-
}
935-
}
936-
};
937-
938-
const sta::Pin* endpoint_pin = endpoint->pin();
939-
sta::LibertyPort* data_port = network_->libertyPort(endpoint_pin);
940-
sta::LibertyCell* cell = data_port->libertyCell();
941-
sta::Instance* inst = network_->instance(endpoint_pin);
942-
943-
for (const sta::Sequential& seq : cell->sequentials()) {
944-
if (!seq.isLatch() || seq.data() == nullptr
945-
|| !seq.data()->hasPort(data_port)) {
946-
continue;
947-
}
948-
949-
if (seq.output() != nullptr) {
950-
add_output_pin(inst, cell, seq.output());
951-
}
952-
if (seq.outputInv() != nullptr) {
953-
add_output_pin(inst, cell, seq.outputInv());
954-
}
955-
}
956-
957-
return output_pins;
958-
}
959-
960-
sta::Slack RepairTargetCollector::latchOutputWorstSlack(
961-
const std::vector<const sta::Pin*>& output_pins) const
962-
{
963-
sta::Slack worst_slack = sta::INF;
964-
965-
for (const sta::Pin* output_pin : output_pins) {
966-
sta::Vertex* output_vertex = graph_->pinDrvrVertex(output_pin);
967-
const sta::Slack output_slack = sta_->slack(output_vertex, max_);
968-
if (sta::delayLess(output_slack, worst_slack, sta_)) {
969-
worst_slack = output_slack;
970-
}
971-
}
972-
973-
return worst_slack;
974-
}
975-
976835
void RepairTargetCollector::collectViolatingStartpoints()
977836
{
978837
violating_startpoints_.clear();

src/rsz/src/RepairTargetCollector.hh

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,6 @@ class RepairTargetCollector
173173

174174
// Public endpoint collection for TNS Phase
175175
void collectViolatingEndpoints();
176-
// Effective slack includes hidden setup debt from latch time borrowing.
177-
// A latch endpoint only pays the part of its borrow that is not covered by
178-
// slack on the latch output path.
179-
sta::Slack getEndpointEffectiveSlack(sta::Vertex* endpoint) const;
180176
sta::Slack getPathSlackByIndex(const sta::Pin* endpoint_pin, int path_index);
181177
const vector<std::pair<const sta::Pin*, sta::Slack>>& getViolatingEndpoints()
182178
const
@@ -301,9 +297,6 @@ class RepairTargetCollector
301297
std::vector<Target>& targets) const;
302298
void collectExpandedPathDriverPins(const sta::PathExpanded& expanded,
303299
set<const sta::Pin*>& pins) const;
304-
std::vector<const sta::Pin*> latchOutputPins(sta::Vertex* endpoint) const;
305-
sta::Slack latchOutputWorstSlack(
306-
const std::vector<const sta::Pin*>& output_pins) const;
307300

308301
// === Cone traversal helpers ==============================================
309302
// Helper functions for cone-based collection

src/rsz/src/policy/SetupLegacyBase.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ bool SetupLegacyBase::repairSetupPin(const sta::Pin* end_pin)
109109
return false;
110110
}
111111

112-
const sta::Slack end_slack
113-
= target_collector_->getEndpointEffectiveSlack(end_vertex);
112+
const sta::Slack end_slack = sta_->slack(end_vertex, max_);
114113
sta::Path* end_path = sta_->vertexWorstSlackPath(end_vertex, max_);
115114
if (end_path == nullptr) {
116115
return false;
@@ -314,8 +313,7 @@ void SetupLegacyBase::saveImprovedCheckpoint(
314313
void SetupLegacyBase::refreshEndpointSlacks(
315314
SetupLegacyBase::EndpointRepairState& endpoint_state)
316315
{
317-
endpoint_state.end_slack
318-
= target_collector_->getEndpointEffectiveSlack(endpoint_state.end);
316+
endpoint_state.end_slack = sta_->slack(endpoint_state.end, max_);
319317
sta_->worstSlack(
320318
max_, endpoint_state.worst_slack, endpoint_state.worst_vertex);
321319
}

src/rsz/src/policy/SetupTnsPolicy.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void SetupTnsPolicy::repairSetupTns(const float setup_slack_margin,
190190
estimate_parasitics_->updateParasitics();
191191
sta_->findRequireds();
192192

193-
endpoint_slack = target_collector_->getEndpointEffectiveSlack(endpoint);
193+
endpoint_slack = sta_->slack(endpoint, max_);
194194
sta::Slack global_wns = 0.0;
195195
sta::Vertex* global_wns_vertex = nullptr;
196196
sta_->worstSlack(max_, global_wns, global_wns_vertex);

src/rsz/test/cpp/TestResizer.cc

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -173,30 +173,6 @@ class TestResizer : public tst::IntegratedFixture
173173
return endpoint;
174174
}
175175

176-
struct SlackPair
177-
{
178-
sta::Slack reported_slack;
179-
sta::Slack effective_slack;
180-
};
181-
182-
SlackPair latchDataSlack(const float input_delay)
183-
{
184-
setupTimeBorrowTiming(input_delay);
185-
186-
RepairTargetCollector collector(&resizer_);
187-
collector.init(0.0f);
188-
189-
sta::Vertex* endpoint = loadVertex("enable_latch/D");
190-
if (endpoint == nullptr) {
191-
return {0.0f, 0.0f};
192-
}
193-
194-
const sta::Slack reported_slack = sta_->slack(endpoint, sta::MinMax::max());
195-
const sta::Slack effective_slack
196-
= collector.getEndpointEffectiveSlack(endpoint);
197-
return {reported_slack, effective_slack};
198-
}
199-
200176
bool hasTargetPin(const std::vector<Target>& targets,
201177
const char* pin_name) const
202178
{
@@ -271,34 +247,6 @@ TEST_F(TestResizer, SwapPinsFeedthroughModNet)
271247
writeAndCompareVerilogOutputFile(test_name, test_name + "_post.v");
272248
}
273249

274-
// A large virtual-clock input delay (0.98) forces the enable latch to borrow
275-
// more time than the downstream logic can absorb (uncovered borrow). In that
276-
// case getEndpointEffectiveSlack() must subtract the uncovered borrow, yielding
277-
// an effective slack strictly worse than the reported slack so that
278-
// repair_timing targets the latch D endpoint.
279-
TEST_F(TestResizer, UncoveredBorrowReducesEffectiveSlack)
280-
{
281-
const SlackPair slack = latchDataSlack(0.98);
282-
const float one_ps = staTime(0.001);
283-
284-
EXPECT_LE(slack.reported_slack, 0.0);
285-
EXPECT_LT(slack.effective_slack, slack.reported_slack - one_ps);
286-
}
287-
288-
// A smaller virtual-clock input delay (0.65) leaves enough downstream setup
289-
// margin to fully cover the latch borrow (covered borrow).
290-
// getEndpointEffectiveSlack() must then leave the reported slack unchanged, so
291-
// that repair_timing does not spuriously optimize the already-covered latch D
292-
// endpoint.
293-
TEST_F(TestResizer, CoveredBorrowKeepsReportedSlack)
294-
{
295-
const SlackPair slack = latchDataSlack(0.65);
296-
const float one_ps = staTime(0.001);
297-
298-
EXPECT_NEAR(slack.reported_slack, 0.0, one_ps);
299-
EXPECT_NEAR(slack.effective_slack, slack.reported_slack, one_ps);
300-
}
301-
302250
TEST_F(TestResizer, LatchThroughPathCollectsLatchDataFaninTargets)
303251
{
304252
setupTimeBorrowTiming(0.98);

0 commit comments

Comments
 (0)