latch dcalc with threads

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2021-11-04 10:30:23 -07:00
parent b3b092a782
commit 65cb291233
4 changed files with 119 additions and 60 deletions

View File

@ -294,14 +294,14 @@ GraphDelayCalc1::delaysInvalid()
iter_->clear();
// No need to keep track of incremental updates any more.
invalid_delays_.clear();
invalid_checks_.clear();
invalid_check_edges_.clear();
invalid_latch_edges_.clear();
}
void
GraphDelayCalc1::delayInvalid(const Pin *pin)
{
if (graph_
&& incremental_) {
if (graph_ && incremental_) {
if (network_->isHierarchical(pin)) {
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
while (edge_iter.hasNext()) {
@ -421,9 +421,13 @@ GraphDelayCalc1::findDelays(Level level)
// Timing checks require slews at both ends of the arc,
// so find their delays after all slews are known.
for (Vertex *check_vertex : invalid_checks_)
findCheckDelays(check_vertex, arc_delay_calc_);
invalid_checks_.clear();
for (Edge *check_edge : invalid_check_edges_)
findCheckEdgeDelays(check_edge, arc_delay_calc_);
invalid_check_edges_.clear();
for (Edge *latch_edge : invalid_latch_edges_)
findLatchEdgeDelays(latch_edge);
invalid_latch_edges_.clear();
delays_exist_ = true;
incremental_ = true;
@ -880,10 +884,34 @@ GraphDelayCalc1::findVertexDelay(Vertex *vertex,
void
GraphDelayCalc1::enqueueTimingChecksEdges(Vertex *vertex)
{
if (vertex->hasChecks()
|| vertex->isCheckClk()) {
UniqueLock lock(check_vertices_lock_);
invalid_checks_.insert(vertex);
if (vertex->hasChecks()) {
VertexInEdgeIterator edge_iter(vertex, graph_);
UniqueLock lock(invalid_edge_lock_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isTimingCheck())
invalid_check_edges_.insert(edge);
}
}
if (vertex->isCheckClk()) {
VertexOutEdgeIterator edge_iter(vertex, graph_);
UniqueLock lock(invalid_edge_lock_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isTimingCheck())
invalid_check_edges_.insert(edge);
}
}
if (network_->isLatchData(vertex->pin())) {
// Latch D->Q arcs have to be re-evaled if level(D) > level(E)
// because levelization does not traverse D->Q arcs to break loops.
VertexOutEdgeIterator edge_iter(vertex, graph_);
UniqueLock lock(invalid_edge_lock_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role() == TimingRole::latchDtoQ())
invalid_latch_edges_.insert(edge);
}
}
}
@ -926,17 +954,23 @@ GraphDelayCalc1::findDriverDelays1(Vertex *drvr_vertex,
initSlew(drvr_vertex);
initWireDelays(drvr_vertex, init_load_slews);
bool delay_changed = false;
bool has_delays = false;
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
Vertex *from_vertex = edge->from(graph_);
// Don't let disabled edges set slews that influence downstream delays.
if (search_pred_->searchFrom(from_vertex)
&& search_pred_->searchThru(edge))
&& search_pred_->searchThru(edge)
&& !edge->role()->isLatchDtoQ()) {
delay_changed |= findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin,
drvr_vertex, multi_drvr, edge,
arc_delay_calc);
has_delays = true;
}
}
if (!has_delays)
zeroSlewAndWireDelays(drvr_vertex);
if (delay_changed && observer_)
observer_->delayChangedTo(drvr_vertex);
return delay_changed;
@ -957,6 +991,21 @@ GraphDelayCalc1::initRootSlews(Vertex *vertex)
}
}
void
GraphDelayCalc1::findLatchEdgeDelays(Edge *edge)
{
Vertex *drvr_vertex = edge->to(graph_);
const Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_pin);
LibertyCell *drvr_cell = network_->libertyCell(drvr_inst);
debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
sdc_network_->pathName(drvr_inst));
bool delay_changed = findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin,
drvr_vertex, nullptr, edge, arc_delay_calc_);
if (delay_changed && observer_)
observer_->delayChangedTo(drvr_vertex);
}
bool
GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
Instance *drvr_inst,
@ -1146,6 +1195,36 @@ GraphDelayCalc1::initSlew(Vertex *vertex)
}
}
void
GraphDelayCalc1::zeroSlewAndWireDelays(Vertex *drvr_vertex)
{
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
DcalcAPIndex ap_index = dcalc_ap->index();
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
for (auto tr : RiseFall::range()) {
// Init drvr slew.
if (!drvr_vertex->slewAnnotated(tr, slew_min_max)) {
DcalcAPIndex ap_index = dcalc_ap->index();
graph_->setSlew(drvr_vertex, tr, ap_index, slew_min_max->initValue());
}
// Init wire delays and slews.
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
if (!graph_->wireDelayAnnotated(wire_edge, tr, ap_index))
graph_->setWireArcDelay(wire_edge, tr, ap_index, 0.0);
// Init load vertex slew.
if (!load_vertex->slewAnnotated(tr, slew_min_max))
graph_->setSlew(load_vertex, tr, ap_index, 0.0);
}
}
}
}
}
// Init wire delays and load slews.
void
GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex,
@ -1162,13 +1241,13 @@ GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex,
Delay delay_init_value(delay_min_max->initValue());
Slew slew_init_value(slew_min_max->initValue());
DcalcAPIndex ap_index = dcalc_ap->index();
for (auto tr : RiseFall::range()) {
if (!graph_->wireDelayAnnotated(wire_edge, tr, ap_index))
graph_->setWireArcDelay(wire_edge, tr, ap_index, delay_init_value);
for (auto rf : RiseFall::range()) {
if (!graph_->wireDelayAnnotated(wire_edge, rf, ap_index))
graph_->setWireArcDelay(wire_edge, rf, ap_index, delay_init_value);
// Init load vertex slew.
if (init_load_slews
&& !load_vertex->slewAnnotated(tr, slew_min_max))
graph_->setSlew(load_vertex, tr, ap_index, slew_init_value);
&& !load_vertex->slewAnnotated(rf, slew_min_max))
graph_->setSlew(load_vertex, rf, ap_index, slew_init_value);
}
}
}
@ -1235,7 +1314,8 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell,
const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this)
&& !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max))
&& !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)
&& !edge->role()->isLatchDtoQ())
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
@ -1247,8 +1327,9 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell,
delay_changed = true;
graph_->setArcDelay(edge, arc, ap_index, gate_delay);
}
annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap,
arc_delay_calc);
if (!edge->role()->isLatchDtoQ())
annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap,
arc_delay_calc);
}
return delay_changed;
}
@ -1445,42 +1526,6 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex,
}
}
void
GraphDelayCalc1::findCheckDelays(Vertex *vertex,
ArcDelayCalc *arc_delay_calc)
{
debugPrint(debug_, "delay_calc", 2, "find checks %s (%s)",
vertex->name(sdc_network_),
network_->cellName(network_->instance(vertex->pin())));
if (vertex->hasChecks()) {
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isTimingCheck())
findCheckEdgeDelays(edge, arc_delay_calc);
}
if (network_->isLatchData(vertex->pin())) {
// Latch D->Q arcs have to be re-evaled if level(D) > level(E)
// because levelization does not traverse D->Q arcs to break loops.
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
Vertex *to_vertex = edge->to(graph_);
if (edge->role() == TimingRole::latchDtoQ())
findVertexDelay(to_vertex, arc_delay_calc_, false);
}
}
}
if (vertex->isCheckClk()) {
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isTimingCheck())
findCheckEdgeDelays(edge, arc_delay_calc);
}
}
}
void
GraphDelayCalc1::findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc)
@ -1491,6 +1536,10 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge,
const Pin *to_pin = to_vertex->pin();
Instance *inst = network_->instance(to_pin);
const LibertyCell *cell = network_->libertyCell(inst);
debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s",
sdc_network_->pathName(inst),
network_->portName(from_vertex->pin()),
network_->portName(to_pin));
bool delay_changed = false;
TimingArcSetArcIterator arc_iter(arc_set);
while (arc_iter.hasNext()) {

View File

@ -138,6 +138,7 @@ protected:
void initWireDelays(Vertex *drvr_vertex,
bool init_load_slews);
void initRootSlews(Vertex *vertex);
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
void findVertexDelay(Vertex *vertex,
ArcDelayCalc *arc_delay_calc,
bool propagate);
@ -160,8 +161,7 @@ protected:
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findCheckDelays(Vertex *vertex,
ArcDelayCalc *arc_delay_calc);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr,
@ -213,9 +213,12 @@ protected:
bool delays_exist_;
// Vertices with invalid -to delays.
VertexSet invalid_delays_;
// Vertices with invalid -from/-to timing checks.
VertexSet invalid_checks_;
std::mutex check_vertices_lock_;
// Timing check edges with invalid delays.
EdgeSet invalid_check_edges_;
// Latch D->Q edges with invalid delays.
EdgeSet invalid_latch_edges_;
// shared by invalid_check_edges_ and invalid_latch_edges_
std::mutex invalid_edge_lock_;
SearchPred *search_pred_;
SearchPred *search_non_latch_pred_;
SearchPred *clk_pred_;

View File

@ -67,6 +67,7 @@ public:
bool isAsyncTimingCheck() const;
bool isNonSeqTimingCheck() const { return is_non_seq_check_; }
bool isDataCheck() const;
bool isLatchDtoQ() const;
const TimingRole *genericRole() const;
const TimingRole *sdfRole() const;
// Timing check data path min/max.

View File

@ -241,6 +241,12 @@ TimingRole::isDataCheck() const
|| this == data_check_hold_;
}
bool
TimingRole::isLatchDtoQ() const
{
return this == latch_d_q_;
}
bool
TimingRole::less(const TimingRole *role1,
const TimingRole *role2)