update latest OpenSTA from upstream 7/25
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
commit
836d704802
|
|
@ -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/*
|
||||||
|
|
|
||||||
3
Brewfile
3
Brewfile
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
370
doc/OpenSTA.fodt
370
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue