update latest OpenSTA from upstream 7/25

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
dsengupta0628 2026-07-25 11:43:45 +00:00
commit 836d704802
15 changed files with 387 additions and 271 deletions

View File

@ -5,7 +5,8 @@ on:
pull_request: pull_request:
jobs: jobs:
build: # Primary native Linux build used for install artifacts.
linux-ubuntu:
if: github.repository_owner != 'The-OpenROAD-Project-private' if: github.repository_owner != 'The-OpenROAD-Project-private'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -51,7 +52,7 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
name: artifact name: artifact-ubuntu
path: | path: |
build/install/* build/install/*
retention-days: 1 retention-days: 1
@ -60,6 +61,78 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
name: result name: result-ubuntu
path: |
test/results/*
# CentOS 7 Docker: old platform still common in EDA environments.
linux-centos:
if: github.repository_owner != 'The-OpenROAD-Project-private'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: true
- name: Build image
run: docker build -f Dockerfile.centos7 --tag sta-centos7 .
- name: Test in container
run: |
mkdir -p test/results
docker run --rm \
-v "$PWD/test/results:/OpenSTA/test/results" \
--entrypoint /bin/bash sta-centos7 \
-c "cd /OpenSTA/test && ./regression || (cat results/diffs && exit 1)"
- name: Upload Test Result
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: result-centos7
path: |
test/results/*
# Native macOS coverage via Brewfile.
macos:
if: github.repository_owner != 'The-OpenROAD-Project-private'
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: true
- name: Install dependencies
run: brew bundle
- name: Build
run: |
eval "$(/opt/homebrew/bin/brew shellenv)"
export PATH="$(brew --prefix flex)/bin:$PATH"
export PATH="$(brew --prefix bison)/bin:$PATH"
export TCL_LIBRARY="$(brew --prefix tcl-tk@8)/lib/libtcl8.6.dylib"
export TCL_INCLUDE_PATH="$(brew --prefix tcl-tk@8)/include/tcl-tk"
export FLEX_INCLUDE_DIR="$(brew --prefix flex)/include"
cmake -S . -B build \
-D TCL_LIBRARY=$TCL_LIBRARY \
-D TCL_INCLUDE_PATH=$TCL_INCLUDE_PATH \
-D FLEX_INCLUDE_DIR=$FLEX_INCLUDE_DIR \
-DCMAKE_BUILD_TYPE=Release
cmake --build build -j "$(sysctl -n hw.ncpu)"
- name: Test
run: |
cd test
./regression || (cat results/diffs && exit 1)
- name: Upload Test Result
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: result-macos
path: | path: |
test/results/* test/results/*

View File

@ -2,8 +2,9 @@ brew "bison"
brew "cmake" brew "cmake"
brew "eigen" brew "eigen"
brew "flex" brew "flex"
brew "googletest"
brew "swig" brew "swig"
brew "tcl-tk@8" brew "tcl-tk@8"
tap "mht208/formal" tap "mht208/formal"
brew "mht208/formal/cudd" brew "mht208/formal/cudd", trusted: true

View File

@ -17,7 +17,7 @@ RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo \
RUN ln -sf /usr/bin/cmake3 /usr/bin/cmake RUN ln -sf /usr/bin/cmake3 /usr/bin/cmake
# Download Bison # Download Bison
RUN wget https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.gz && \ RUN wget https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz && \
tar -xvf bison-3.8.2.tar.gz && \ tar -xvf bison-3.8.2.tar.gz && \
rm bison-3.8.2.tar.gz rm bison-3.8.2.tar.gz
@ -42,7 +42,8 @@ RUN source /opt/rh/devtoolset-11/enable && \
make install make install
# Download TCL # Download TCL
RUN wget http://prdownloads.sourceforge.net/tcl/tcl8.6.16-src.tar.gz && \ RUN wget https://sourceforge.net/projects/tcl/files/Tcl/8.6.16/tcl8.6.16-src.tar.gz/download \
-O tcl8.6.16-src.tar.gz && \
tar -xvf tcl8.6.16-src.tar.gz && \ tar -xvf tcl8.6.16-src.tar.gz && \
rm tcl8.6.16-src.tar.gz rm tcl8.6.16-src.tar.gz

View File

@ -213,7 +213,6 @@ GraphDelayCalc::delaysInvalid()
debugPrint(debug_, "delay_calc", 1, "delays invalid"); debugPrint(debug_, "delay_calc", 1, "delays invalid");
delays_exist_ = false; delays_exist_ = false;
delays_seeded_ = false; delays_seeded_ = false;
incremental_ = false;
iter_->clear(); iter_->clear();
// No need to keep track of incremental updates any more. // No need to keep track of incremental updates any more.
invalid_delays_.clear(); invalid_delays_.clear();
@ -224,7 +223,7 @@ GraphDelayCalc::delaysInvalid()
void void
GraphDelayCalc::delayInvalid(const Pin *pin) GraphDelayCalc::delayInvalid(const Pin *pin)
{ {
if (graph_ && incremental_) { if (graph_ && delays_exist_) {
if (network_->isHierarchical(pin)) { if (network_->isHierarchical(pin)) {
EdgesThruHierPinIterator edge_iter(pin, network_, graph_); EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
while (edge_iter.hasNext()) { while (edge_iter.hasNext()) {
@ -248,7 +247,7 @@ GraphDelayCalc::delayInvalid(Vertex *vertex)
{ {
debugPrint(debug_, "delay_calc", 2, "delay invalid {}", debugPrint(debug_, "delay_calc", 2, "delay invalid {}",
vertex->to_string(this)); vertex->to_string(this));
if (incremental_) { if (delays_exist_) {
invalid_delays_.insert(vertex); invalid_delays_.insert(vertex);
// Invalidate driver that triggers dcalc for multi-driver nets. // Invalidate driver that triggers dcalc for multi-driver nets.
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
@ -274,7 +273,7 @@ void
GraphDelayCalc::deleteVertexBefore(Vertex *vertex) GraphDelayCalc::deleteVertexBefore(Vertex *vertex)
{ {
iter_->deleteVertexBefore(vertex); iter_->deleteVertexBefore(vertex);
if (incremental_) if (delays_exist_)
invalid_delays_.erase(vertex); invalid_delays_.erase(vertex);
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
if (multi_drvr) { if (multi_drvr) {
@ -329,7 +328,7 @@ FindVertexDelays::copy() const
void void
FindVertexDelays::visit(Vertex *vertex) FindVertexDelays::visit(Vertex *vertex)
{ {
graph_delay_calc_->findVertexDelay(vertex, arc_delay_calc_, true); graph_delay_calc_->findVertexDelay(vertex, arc_delay_calc_);
} }
// The logical structure of incremental delay calculation closely // The logical structure of incremental delay calculation closely
@ -348,7 +347,7 @@ GraphDelayCalc::findDelays(Level level)
} }
else else
iter_->ensureSize(); iter_->ensureSize();
if (incremental_) if (delays_exist_)
seedInvalidDelays(); seedInvalidDelays();
if (!iter_->empty()) { if (!iter_->empty()) {
@ -367,7 +366,6 @@ GraphDelayCalc::findDelays(Level level)
invalid_latch_edges_.clear(); invalid_latch_edges_.clear();
delays_exist_ = true; delays_exist_ = true;
incremental_ = true;
debugPrint(debug_, "delay_calc", 1, "found {} delays", dcalc_count); debugPrint(debug_, "delay_calc", 1, "found {} delays", dcalc_count);
stats.report("Delay calc"); stats.report("Delay calc");
} }
@ -674,13 +672,12 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
void void
GraphDelayCalc::findDelays(Vertex *drvr_vertex) GraphDelayCalc::findDelays(Vertex *drvr_vertex)
{ {
findVertexDelay(drvr_vertex, arc_delay_calc_, true); findVertexDelay(drvr_vertex, arc_delay_calc_);
} }
void void
GraphDelayCalc::findVertexDelay(Vertex *vertex, GraphDelayCalc::findVertexDelay(Vertex *vertex,
ArcDelayCalc *arc_delay_calc, ArcDelayCalc *arc_delay_calc)
bool propagate)
{ {
const Pin *pin = vertex->pin(); const Pin *pin = vertex->pin();
debugPrint(debug_, "delay_calc", 2, "find delays {} ({})", debugPrint(debug_, "delay_calc", 2, "find delays {} ({})",
@ -692,32 +689,38 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|| (vertex->isBidirectDriver() || (vertex->isBidirectDriver()
&& network_->isTopLevelPort(pin))) && network_->isTopLevelPort(pin)))
seedRootSlew(vertex, arc_delay_calc); seedRootSlew(vertex, arc_delay_calc);
else { else if (network_->isLeaf(pin)
if (network_->isLeaf(pin)) { && vertex->isDriver(network_)) {
if (vertex->isDriver(network_)) { LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(vertex);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(vertex); DrvrLoadSlews load_slews_prev;
DrvrLoadSlews load_slews_prev; if (delays_exist_)
if (incremental_) load_slews_prev = loadSlews(load_pin_index_map);
load_slews_prev = loadSlews(load_pin_index_map); findDriverDelays(vertex, arc_delay_calc, load_pin_index_map);
findDriverDelays(vertex, arc_delay_calc, load_pin_index_map); if (network_->direction(pin)->isInternal())
if (propagate) { enqueueCheckEdges(vertex);
if (network_->direction(pin)->isInternal()) graph_->visitFanouts(vertex, search_non_latch_pred_,
enqueueTimingChecksEdges(vertex); [this, &load_slews_prev, &load_pin_index_map]
// Enqueue adjacent vertices even if the load slews did not (Vertex *fanout) {
// change when non-incremental to stride past annotations. // Enqueue adjacent vertices even if the load slew
if (!incremental_ // did not change when non-incremental to stride
|| loadSlewsChanged(load_slews_prev, load_pin_index_map)) // past annotations.
iter_->enqueueFanout(vertex); if (!delays_exist_
} || loadSlewChanged(fanout, load_slews_prev,
} load_pin_index_map)) {
else { iter_->enqueue(fanout);
// Load vertex. fanout->setBfsPredecessorChanged(true);
enqueueTimingChecksEdges(vertex); }
// Enqueue driver vertices from this input load. });
if (propagate) }
iter_->enqueueFanout(vertex); else if (vertex->isLoad(network_)) {
} // Load vertex.
} // Includes top level bidirect load vertex with wire edge to bidirect driver.
enqueueCheckEdges(vertex);
graph_->visitFanouts(vertex, search_non_latch_pred_,
[this] (Vertex *fanout) {
iter_->enqueue(fanout);
fanout->setBfsPredecessorChanged(true);
});
} }
} }
@ -737,24 +740,25 @@ GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map)
} }
bool bool
GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &load_slews_prev, GraphDelayCalc::loadSlewChanged(Vertex *load_vertex,
LoadPinIndexMap &load_pin_index_map) DrvrLoadSlews &load_slews_prev,
LoadPinIndexMap &load_pin_index_map)
{ {
if (load_slews_prev.empty())
return true;
size_t index = load_pin_index_map[load_vertex->pin()];
SlewSeq &slews_prev = load_slews_prev[index];;
size_t slew_count = graph_->slewCount(); size_t slew_count = graph_->slewCount();
for (auto const [pin, index] : load_pin_index_map) { for (size_t i = 0; i < slew_count; i++) {
Vertex *load_vertex = graph_->pinLoadVertex(pin); const Slew slew = graph_->slew(load_vertex, i);
SlewSeq &slews_prev = load_slews_prev[index];; if (!delayEqual(slew, slews_prev[i], this))
for (size_t i = 0; i < slew_count; i++) { return true;
const Slew slew = graph_->slew(load_vertex, i);
if (!delayEqual(slew, slews_prev[i], this))
return true;
}
} }
return false; return false;
} }
void void
GraphDelayCalc::enqueueTimingChecksEdges(Vertex *vertex) GraphDelayCalc::enqueueCheckEdges(Vertex *vertex)
{ {
if (vertex->hasChecks()) { if (vertex->hasChecks()) {
VertexInEdgeIterator edge_iter(vertex, graph_); VertexInEdgeIterator edge_iter(vertex, graph_);
@ -1180,10 +1184,10 @@ GraphDelayCalc::annotateDelaysSlews(Edge *edge,
dcalc_result.drvrSlew(), scene, min_max); dcalc_result.drvrSlew(), scene, min_max);
if (!edge->role()->isLatchDtoQ()) { if (!edge->role()->isLatchDtoQ()) {
Vertex *drvr_vertex = edge->to(graph_); Vertex *drvr_vertex = edge->to(graph_);
delay_changed |= annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(), annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(),
dcalc_result, dcalc_result,
load_pin_index_map, delay_zero, true, load_pin_index_map, delay_zero, true,
scene, min_max); scene, min_max);
} }
return delay_changed; return delay_changed;
} }
@ -1238,7 +1242,7 @@ GraphDelayCalc::annotateDelaySlew(Edge *edge,
// Annotate wire arc delays and load pin slews. // Annotate wire arc delays and load pin slews.
// extra_delay is additional wire delay to add to delay returned // extra_delay is additional wire delay to add to delay returned
// by the delay calculator. // by the delay calculator.
bool void
GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf, const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result, ArcDcalcResult &dcalc_result,
@ -1249,7 +1253,6 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
const MinMax *min_max) const MinMax *min_max)
{ {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
bool changed = false;
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) { while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next(); Edge *wire_edge = edge_iter.next();
@ -1264,20 +1267,17 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
load_vertex->to_string(this), load_vertex->to_string(this),
delayAsString(wire_delay, this), delayAsString(wire_delay, this),
delayAsString(load_slew, this)); delayAsString(load_slew, this));
bool load_changed = false;
if (!load_vertex->slewAnnotated(drvr_rf, min_max)) { if (!load_vertex->slewAnnotated(drvr_rf, min_max)) {
if (drvr_vertex->slewAnnotated(drvr_rf, min_max)) { if (drvr_vertex->slewAnnotated(drvr_rf, min_max)) {
// Copy the driver slew to the load if it is annotated. // Copy the driver slew to the load if it is annotated.
const Slew drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); const Slew drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew);
load_changed = true;
} }
else { else {
const Slew slew = graph_->slew(load_vertex, drvr_rf, ap_index); const Slew slew = graph_->slew(load_vertex, drvr_rf, ap_index);
if (!merge if (!merge
|| delayGreater(load_slew, slew, min_max, this)) { || delayGreater(load_slew, slew, min_max, this)) {
graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew);
load_changed = true;
} }
} }
} }
@ -1290,18 +1290,12 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
if (!merge if (!merge
|| delayGreater(wire_delay_extra, delay, min_max, this)) { || delayGreater(wire_delay_extra, delay, min_max, this)) {
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra); graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);
load_changed = true; if (observer_)
observer_->delayChangedTo(load_vertex);
} }
} }
if (load_changed && observer_)
observer_->delayChangedTo(load_vertex);
// Enqueue bidirect driver from load vertex.
if (bidirectDrvrSlewFromLoad(load_pin))
iter_->enqueue(graph_->pinDrvrVertex(load_pin));
changed |= load_changed;
} }
} }
return changed;
} }
LoadPinIndexMap LoadPinIndexMap

View File

@ -65,7 +65,6 @@ PrimaDelayCalc::PrimaDelayCalc(StaState *sta) :
PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) : PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) :
DelayCalcBase(dcalc), DelayCalcBase(dcalc),
pin_node_map_(network_), pin_node_map_(network_),
node_index_map_(dcalc.node_index_map_),
prima_order_(dcalc.prima_order_), prima_order_(dcalc.prima_order_),
watch_pin_values_(network_), watch_pin_values_(network_),
table_dcalc_(makeDmpCeffElmoreDelayCalc(this)) table_dcalc_(makeDmpCeffElmoreDelayCalc(this))

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1053,6 +1053,7 @@ Vertex::init(Pin *pin,
has_downstream_clk_pin_ = false; has_downstream_clk_pin_ = false;
visited1_ = false; visited1_ = false;
visited2_ = false; visited2_ = false;
bfs_predecessor_changed_ = false;
has_sim_value_ = false; has_sim_value_ = false;
level_ = 0; level_ = 0;
slew_annotated_ = false; slew_annotated_ = false;
@ -1115,6 +1116,23 @@ Vertex::isDriver(const Network *network) const
|| dir->isInternal()))); || dir->isInternal())));
} }
bool
Vertex::isLoad(const Network *network) const
{
PortDirection *dir = network->direction(pin_);
bool top_level_port = network->isTopLevelPort(pin_);
return ((top_level_port
&& (dir->isOutput()
|| (dir->isBidirect()
&& !is_bidirect_drvr_)))
|| (!top_level_port
&& (dir->isInput()
|| dir->isTristate()
|| (dir->isBidirect()
&& !is_bidirect_drvr_)
|| dir->isInternal())));
}
void void
Vertex::setLevel(Level level) Vertex::setLevel(Level level)
{ {
@ -1264,6 +1282,12 @@ Vertex::setBfsInQueue(BfsIndex index,
bfs_in_queue_ &= ~(1 << static_cast<unsigned>(index)); bfs_in_queue_ &= ~(1 << static_cast<unsigned>(index));
} }
void
Vertex::setBfsPredecessorChanged(bool changed)
{
bfs_predecessor_changed_ = changed;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// //
// Edge // Edge

View File

@ -255,6 +255,7 @@ public:
std::string name(const Network *network) const; std::string name(const Network *network) const;
[[nodiscard]] bool isBidirectDriver() const { return is_bidirect_drvr_; } [[nodiscard]] bool isBidirectDriver() const { return is_bidirect_drvr_; }
[[nodiscard]] bool isDriver(const Network *network) const; [[nodiscard]] bool isDriver(const Network *network) const;
[[nodiscard]] bool isLoad(const Network *network) const;
Level level() const { return level_; } Level level() const { return level_; }
void setLevel(Level level); void setLevel(Level level);
[[nodiscard]] bool visited() const { return visited1_; } [[nodiscard]] bool visited() const { return visited1_; }
@ -288,6 +289,8 @@ public:
void setHasDownstreamClkPin(bool has_clk_pin); void setHasDownstreamClkPin(bool has_clk_pin);
[[nodiscard]] bool bfsInQueue(BfsIndex index) const; [[nodiscard]] bool bfsInQueue(BfsIndex index) const;
void setBfsInQueue(BfsIndex index, bool value); void setBfsInQueue(BfsIndex index, bool value);
bool bfsPredecessorChanged() const { return bfs_predecessor_changed_; }
void setBfsPredecessorChanged(bool changed);
[[nodiscard]] bool isRegClk() const { return is_reg_clk_; } [[nodiscard]] bool isRegClk() const { return is_reg_clk_; }
// Has sim value in some mode. // Has sim value in some mode.
[[nodiscard]] bool hasSimValue() const { return has_sim_value_; } [[nodiscard]] bool hasSimValue() const { return has_sim_value_; }
@ -335,6 +338,7 @@ protected:
unsigned int has_downstream_clk_pin_:1; unsigned int has_downstream_clk_pin_:1;
unsigned int visited1_:1; unsigned int visited1_:1;
unsigned int visited2_:1; unsigned int visited2_:1;
unsigned int bfs_predecessor_changed_:1;
unsigned int has_sim_value_:1; unsigned int has_sim_value_:1;
int level_:Graph::vertex_level_bits; // 24 int level_:Graph::vertex_level_bits; // 24
unsigned int slew_annotated_:slew_annotated_bits; // 4 unsigned int slew_annotated_:slew_annotated_bits; // 4

View File

@ -232,12 +232,12 @@ protected:
void zeroSlewAndWireDelays(Vertex *drvr_vertex, void zeroSlewAndWireDelays(Vertex *drvr_vertex,
const RiseFall *rf); const RiseFall *rf);
void findVertexDelay(Vertex *vertex, void findVertexDelay(Vertex *vertex,
ArcDelayCalc *arc_delay_calc, ArcDelayCalc *arc_delay_calc);
bool propagate);
DrvrLoadSlews loadSlews(LoadPinIndexMap &load_pin_index_map); DrvrLoadSlews loadSlews(LoadPinIndexMap &load_pin_index_map);
bool loadSlewsChanged(DrvrLoadSlews &load_slews_prev, void enqueueCheckEdges(Vertex *vertex);
LoadPinIndexMap &load_pin_index_map); bool loadSlewChanged(Vertex *load_vertex,
void enqueueTimingChecksEdges(Vertex *vertex); DrvrLoadSlews &load_slews_prev,
LoadPinIndexMap &load_pin_index_map);
bool annotateDelaysSlews(Edge *edge, bool annotateDelaysSlews(Edge *edge,
const TimingArc *arc, const TimingArc *arc,
ArcDcalcResult &dcalc_result, ArcDcalcResult &dcalc_result,
@ -251,7 +251,7 @@ protected:
const Slew &gate_slew, const Slew &gate_slew,
const Scene *scene, const Scene *scene,
const MinMax *min_max); const MinMax *min_max);
bool annotateLoadDelays(Vertex *drvr_vertex, void annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf, const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result, ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map, LoadPinIndexMap &load_pin_index_map,
@ -296,7 +296,6 @@ protected:
// Observer for edge delay changes. // Observer for edge delay changes.
DelayCalcObserver *observer_{nullptr}; DelayCalcObserver *observer_{nullptr};
bool delays_seeded_{false}; bool delays_seeded_{false};
bool incremental_{false};
bool delays_exist_{false}; bool delays_exist_{false};
// Vertices with invalid -to delays. // Vertices with invalid -to delays.
VertexSet invalid_delays_; VertexSet invalid_delays_;

View File

@ -1008,6 +1008,8 @@ public:
void reportPathEnds(PathEndSeq *ends); void reportPathEnds(PathEndSeq *ends);
ReportPath *reportPath() { return report_path_; } ReportPath *reportPath() { return report_path_; }
void reportPath(const Path *path); void reportPath(const Path *path);
// For debugging.
void reportPathVerbose(const Path *path);
// Report clk skews for clks. // Report clk skews for clks.
void reportClkSkew(ConstClockSeq &clks, void reportClkSkew(ConstClockSeq &clks,

View File

@ -118,6 +118,15 @@ ClkInfo::crprClkVertexId(const StaState *sta) const
return crpr_clk_path_.vertexId(sta); return crpr_clk_path_.vertexId(sta);
} }
const MinMax *
ClkInfo::crprClkMinMax(const StaState *sta) const
{
if (crpr_clk_path_.isNull())
return nullptr;
else
return crpr_clk_path_.tag(sta)->minMax();
}
Path * Path *
ClkInfo::crprClkPath(const StaState *sta) ClkInfo::crprClkPath(const StaState *sta)
{ {

View File

@ -78,13 +78,14 @@ public:
// Null for clocks because the path cannot point to itself. // Null for clocks because the path cannot point to itself.
Path *crprClkPath(const StaState *sta); Path *crprClkPath(const StaState *sta);
const Path *crprClkPath(const StaState *sta) const; const Path *crprClkPath(const StaState *sta) const;
const Path *crprClkPathRaw() const;
VertexId crprClkVertexId(const StaState *sta) const; VertexId crprClkVertexId(const StaState *sta) const;
const MinMax *crprClkMinMax(const StaState *sta) const;
bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); } bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); }
// This clk_info/tag is used for a generated clock source path. // This clk_info/tag is used for a generated clock source path.
bool isGenClkSrcPath() const { return is_gen_clk_src_path_; } bool isGenClkSrcPath() const { return is_gen_clk_src_path_; }
size_t hash() const { return hash_; } size_t hash() const { return hash_; }
bool crprPathRefsFilter() const { return crpr_path_refs_filter_; } bool crprPathRefsFilter() const { return crpr_path_refs_filter_; }
const Path *crprClkPathRaw() const;
static int cmp(const ClkInfo *clk_info1, static int cmp(const ClkInfo *clk_info1,
const ClkInfo *clk_info2, const ClkInfo *clk_info2,

View File

@ -1396,13 +1396,15 @@ ArrivalVisitor::pruneCrprArrivals()
size_t path_index = path_itr->second; size_t path_index = path_itr->second;
const ClkInfo *clk_info = tag->clkInfo(); const ClkInfo *clk_info = tag->clkInfo();
bool deleted_tag = false; bool deleted_tag = false;
if (!tag->isClock() && clk_info->hasCrprClkPin()) { if (!tag->isClock()
const MinMax *min_max = tag->minMax(); && clk_info->hasCrprClkPin()) {
Path *path_no_crpr = tag_bldr_no_crpr_->tagMatchPath(tag); Path *path_no_crpr = tag_bldr_no_crpr_->tagMatchPath(tag);
if (path_no_crpr) { if (path_no_crpr
&& path_no_crpr->tag(this) != tag) {
Arrival max_arrival = path_no_crpr->arrival(); Arrival max_arrival = path_no_crpr->arrival();
const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this); const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr); Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
const MinMax *min_max = tag->minMax();
Arrival max_arrival_max_crpr = (min_max == MinMax::max()) Arrival max_arrival_max_crpr = (min_max == MinMax::max())
? delayDiff(max_arrival, max_crpr, this) ? delayDiff(max_arrival, max_crpr, this)
: delaySum(max_arrival, max_crpr, this); : delaySum(max_arrival, max_crpr, this);
@ -1412,11 +1414,10 @@ ArrivalVisitor::pruneCrprArrivals()
delayAsString(max_crpr, this), delayAsString(max_crpr, this),
delayAsString(max_arrival_max_crpr, this)); delayAsString(max_arrival_max_crpr, this));
Arrival arrival = tag_bldr_->arrival(path_index); Arrival arrival = tag_bldr_->arrival(path_index);
// Latch D->Q path uses enable min so crpr clk path min/max
// does not match the path min/max.
if (delayGreater(max_arrival_max_crpr, arrival, min_max, this) if (delayGreater(max_arrival_max_crpr, arrival, min_max, this)
&& clk_info_no_crpr->crprClkPath(this)->minMax(this) // Latch D->Q path uses enable min so crpr clk path min/max
== clk_info->crprClkPath(this)->minMax(this)) { // does not match the path min/max.
&& clk_info_no_crpr->crprClkMinMax(this) == clk_info->crprClkMinMax(this)) {
debugPrint(debug_, "search", 3, " pruned {}", debugPrint(debug_, "search", 3, " pruned {}",
tag->to_string(this)); tag->to_string(this));
path_itr = path_index_map.erase(path_itr); path_itr = path_index_map.erase(path_itr);

View File

@ -2862,6 +2862,14 @@ Sta::reportPath(const Path *path)
report_path_->reportPath(path); report_path_->reportPath(path);
} }
void
Sta::reportPathVerbose(const Path *path)
{
const StringSeq field_names = {"input_pins", "slew", "capacitance"};
setReportPathFields(field_names);
report_path_->reportPath(path);
}
void void
Sta::updateTiming(bool full) Sta::updateTiming(bool full)
{ {