Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2025-02-12 00:55:01 +00:00
commit 6e95d93a44
20 changed files with 467 additions and 757 deletions

View File

@ -65,8 +65,7 @@ compiled locally. Derivative works are supported as long as they
adhere to the GPL license requirements. However, OpenSTA is not
supported by a public community of developers as many other open
source projects are. The copyright and develpment are exclusive to
Parallax Software. Contributors must signing the Contributor License
Agreement (doc/CLA.txt) when submitting pull requests.
Parallax Software.
Removing copyright and license notices from OpenSTA sources (or any
other open source project for that matter) is illegal. This should be
@ -259,8 +258,12 @@ Contributions that claim 4% performance improvements in OpenROAD flow
scripts will largely be ignored. Small performance improvements
simply do not justify the time requied to audit and verify the changes.
Contributions that add dependencies on external libraries like boost
will not be accepted.
Contributions that add dependencies on external libraries like boost,
abseil and Intel TBB will not be accepted.
As the author of OpenSTA I vastly prefer writing code to reviewing
code. I don't have the patience to go round after round to correct
code formatting that is not consistent with the rest of the code.
## Authors

View File

@ -621,10 +621,15 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
DrvrLoadSlews
GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map)
{
size_t slew_count = graph_->slewCount();
DrvrLoadSlews load_slews(load_pin_index_map.size());
for (auto const [pin, index] : load_pin_index_map) {
Vertex *load_vertex = graph_->pinLoadVertex(pin);
load_slews[index] = graph_->slews(load_vertex);
SlewSeq &slews = load_slews[index];;
slews.resize(slew_count);
Slew *vertex_slews = load_vertex->slews();
for (size_t i = 0; i < slew_count; i++)
slews[i] = vertex_slews[i];
}
return load_slews;
}
@ -633,11 +638,12 @@ bool
GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &load_slews_prev,
LoadPinIndexMap &load_pin_index_map)
{
size_t slew_count = graph_->slewCount();
for (auto const [pin, index] : load_pin_index_map) {
Vertex *load_vertex = graph_->pinLoadVertex(pin);
const SlewSeq slews = graph_->slews(load_vertex);
const SlewSeq &slews_prev = load_slews_prev[index];
for (size_t i = 0; i < slews.size(); i++) {
SlewSeq &slews_prev = load_slews_prev[index];;
const Slew *slews = load_vertex->slews();
for (size_t i = 0; i < slew_count; i++) {
if (!delayEqual(slews[i], slews_prev[i]))
return true;
}

View File

@ -46,14 +46,11 @@ namespace sta {
Graph::Graph(StaState *sta,
int slew_rf_count,
bool have_arc_delays,
DcalcAPIndex ap_count) :
StaState(sta),
vertices_(nullptr),
edges_(nullptr),
arc_count_(0),
slew_rf_count_(slew_rf_count),
have_arc_delays_(have_arc_delays),
ap_count_(ap_count),
period_check_annotations_(nullptr),
reg_clk_vertices_(new VertexSet(graph_))
@ -64,11 +61,11 @@ Graph::Graph(StaState *sta,
Graph::~Graph()
{
delete vertices_;
edges_->clear();
delete edges_;
vertices_->clear();
delete vertices_;
delete reg_clk_vertices_;
deleteSlewTables();
deleteArcDelayTables();
removePeriodCheckAnnotations();
}
@ -90,8 +87,6 @@ Graph::makeVerticesAndEdges()
{
vertices_ = new VertexTable;
edges_ = new EdgeTable;
makeSlewTables(ap_count_);
makeArcDelayTables(ap_count_);
LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator();
while (leaf_iter->hasNext()) {
@ -440,7 +435,7 @@ Graph::makeVertex(Pin *pin,
{
Vertex *vertex = vertices_->make();
vertex->init(pin, is_bidirect_drvr, is_reg_clk);
makeVertexSlews(vertex);
initSlews(vertex);
if (is_reg_clk)
reg_clk_vertices_->insert(vertex);
return vertex;
@ -491,7 +486,7 @@ Graph::deleteVertex(Vertex *vertex)
Edge *edge = Graph::edge(edge_id);
next_id = edge->vertex_in_link_;
deleteOutEdge(edge->from(this), edge);
arc_count_ -= edge->timingArcSet()->arcCount();
edge->clear();
edges_->destroy(edge);
}
// Delete edges from vertex.
@ -499,9 +494,10 @@ Graph::deleteVertex(Vertex *vertex)
Edge *edge = Graph::edge(edge_id);
next_id = edge->vertex_out_next_;
deleteInEdge(edge->to(this), edge);
arc_count_ -= edge->timingArcSet()->arcCount();
edge->clear();
edges_->destroy(edge);
}
vertex->clear();
vertices_->destroy(vertex);
}
@ -577,155 +573,90 @@ Graph::gateEdgeArc(const Pin *in_pin,
Arrival *
Graph::makeArrivals(Vertex *vertex,
uint32_t count)
uint32_t count)
{
if (vertex->arrivals() != arrival_null)
debugPrint(debug_, "graph", 1, "arrival leak");
Arrival *arrivals;
ArrivalId id;
{
LockGuard lock(arrivals_lock_);
arrivals_.make(count, arrivals, id);
}
vertex->setArrivals(id);
Arrival *arrivals = new Arrival[count];
vertex->setArrivals(arrivals);
return arrivals;
}
Arrival *
Graph::arrivals(Vertex *vertex)
Graph::arrivals(const Vertex *vertex) const
{
return arrivals_.pointer(vertex->arrivals());
return vertex->arrivals();
}
void
Graph::deleteArrivals(Vertex *vertex,
uint32_t count)
Graph::deleteArrivals(Vertex *vertex)
{
{
LockGuard lock(arrivals_lock_);
arrivals_.destroy(vertex->arrivals(), count);
}
vertex->setArrivals(arrival_null);
vertex->setArrivals(nullptr);
}
Required *
Graph::requireds(const Vertex *vertex) const
{
return vertex->requireds();
}
Required *
Graph::makeRequireds(Vertex *vertex,
uint32_t count)
{
if (vertex->requireds() != arrival_null)
debugPrint(debug_, "graph", 1, "required leak");
Required *requireds;
ArrivalId id;
{
LockGuard lock(requireds_lock_);
requireds_.make(count, requireds, id);
}
vertex->setRequireds(id);
Required *requireds = new Arrival[count];
vertex->setRequireds(requireds);
return requireds;
}
Required *
Graph::requireds(Vertex *vertex)
void
Graph::deleteRequireds(Vertex *vertex)
{
return requireds_.pointer(vertex->requireds());
vertex->setRequireds(nullptr);
}
void
Graph::deleteRequireds(Vertex *vertex,
uint32_t count)
PathVertexRep *
Graph::prevPaths(const Vertex *vertex) const
{
{
LockGuard lock(requireds_lock_);
requireds_.destroy(vertex->requireds(), count);
}
vertex->setRequireds(arrival_null);
return vertex->prevPaths();
}
PathVertexRep *
Graph::makePrevPaths(Vertex *vertex,
uint32_t count)
uint32_t count)
{
PathVertexRep *prev_paths;
PrevPathId id;
{
LockGuard lock(prev_paths_lock_);
prev_paths_.make(count, prev_paths, id);
}
vertex->setPrevPaths(id);
PathVertexRep *prev_paths = new PathVertexRep[count];
vertex->setPrevPaths(prev_paths);
return prev_paths;
}
PathVertexRep *
Graph::prevPaths(Vertex *vertex) const
void
Graph::deletePrevPaths(Vertex *vertex)
{
return prev_paths_.pointer(vertex->prevPaths());
vertex->setPrevPaths(nullptr);
}
void
Graph::deletePrevPaths(Vertex *vertex,
uint32_t count)
Graph::deletePaths(Vertex *vertex)
{
if (vertex->prevPaths() != object_id_null) {
{
LockGuard lock(prev_paths_lock_);
prev_paths_.destroy(vertex->prevPaths(), count);
}
vertex->setPrevPaths(object_id_null);
}
}
void
Graph::deletePaths()
{
arrivals_.clear();
requireds_.clear();
prev_paths_.clear();
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
vertex->setArrivals(arrival_null);
vertex->setRequireds(arrival_null);
vertex->setPrevPaths(object_id_null);
vertex->tag_group_index_ = tag_group_index_max;
vertex->crpr_path_pruning_disabled_ = false;
}
}
void
Graph::deletePaths(Vertex *vertex,
uint32_t count)
{
if (vertex->arrivals() != arrival_null) {
LockGuard lock(arrivals_lock_);
arrivals_.destroy(vertex->arrivals(), count);
vertex->setArrivals(arrival_null);
vertex->tag_group_index_ = tag_group_index_max;
vertex->crpr_path_pruning_disabled_ = false;
}
if (vertex->requireds() != arrival_null) {
requireds_.destroy(vertex->requireds(), count);
vertex->setRequireds(arrival_null);
}
if (vertex->prevPaths() != object_id_null) {
prev_paths_.destroy(vertex->prevPaths(), count);
vertex->setPrevPaths(object_id_null);
}
deleteArrivals(vertex);
deleteRequireds(vertex);
deletePrevPaths(vertex);
vertex->tag_group_index_ = tag_group_index_max;
vertex->crpr_path_pruning_disabled_ = false;
}
////////////////////////////////////////////////////////////////
const Slew &
Graph::slew(const Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index)
const RiseFall *rf,
DcalcAPIndex ap_index)
{
if (slew_rf_count_) {
int table_index =
(slew_rf_count_ == 1) ? ap_index : ap_index*slew_rf_count_+rf->index();
DelayTable *table = slew_tables_[table_index];
VertexId vertex_id = id(vertex);
return table->ref(vertex_id);
const Slew *slews = vertex->slews();
size_t slew_index = (slew_rf_count_ == 1)
? ap_index
: ap_index*slew_rf_count_+rf->index();
return slews[slew_index];
}
else {
static Slew slew(0.0);
@ -735,34 +666,24 @@ Graph::slew(const Vertex *vertex,
void
Graph::setSlew(Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index,
const Slew &slew)
const RiseFall *rf,
DcalcAPIndex ap_index,
const Slew &slew)
{
if (slew_rf_count_) {
int table_index =
(slew_rf_count_ == 1) ? ap_index : ap_index*slew_rf_count_+rf->index();
DelayTable *table = slew_tables_[table_index];
VertexId vertex_id = id(vertex);
Slew &vertex_slew = table->ref(vertex_id);
vertex_slew = slew;
Slew *slews = vertex->slews();
if (slews == nullptr) {
int slew_count = slew_rf_count_ * ap_count_;
slews = new Slew[slew_count];
vertex->setSlews(slews);
}
size_t slew_index = (slew_rf_count_ == 1)
? ap_index
: ap_index*slew_rf_count_+rf->index();
slews[slew_index] = slew;
}
}
SlewSeq
Graph::slews(Vertex *vertex)
{
SlewSeq slews;
VertexId vertex_id = id(vertex);
DcalcAPIndex rf_ap_count = slew_rf_count_ * ap_count_;
for (DcalcAPIndex i = 0; i < rf_ap_count; i++) {
DelayTable *table = slew_tables_[i];
Slew &slew = table->ref(vertex_id);
slews.push_back(slew);
}
return slews;
}
////////////////////////////////////////////////////////////////
Edge *
@ -784,8 +705,6 @@ Graph::makeEdge(Vertex *from,
{
Edge *edge = edges_->make();
edge->init(id(from), id(to), arc_set);
makeEdgeArcDelays(edge);
arc_count_ += arc_set->arcCount();
// Add out edge to from vertex.
EdgeId next = from->out_edges_;
edge->vertex_out_next_ = next;
@ -799,6 +718,7 @@ Graph::makeEdge(Vertex *from,
edge->vertex_in_link_ = to->in_edges_;
to->in_edges_ = edge_id;
initArcDelays(edge);
return edge;
}
@ -809,63 +729,18 @@ Graph::deleteEdge(Edge *edge)
Vertex *to = edge->to(this);
deleteOutEdge(from, edge);
deleteInEdge(to, edge);
arc_count_ -= edge->timingArcSet()->arcCount();
edge->clear();
edges_->destroy(edge);
}
void
Graph::makeArcDelayTables(DcalcAPIndex ap_count)
{
if (have_arc_delays_) {
arc_delays_.resize(ap_count);
for (DcalcAPIndex i = 0; i < ap_count; i++)
arc_delays_[i] = new DelayTable();
}
}
void
Graph::deleteArcDelayTables()
{
arc_delays_.deleteContentsClear();
}
void
Graph::makeEdgeArcDelays(Edge *edge)
{
if (have_arc_delays_) {
int arc_count = edge->timingArcSet()->arcCount();
ArcId arc_id = 0;
for (DcalcAPIndex i = 0; i < ap_count_; i++) {
DelayTable *table = arc_delays_[i];
ArcDelay *arc_delays;
table->make(arc_count, arc_delays, arc_id);
for (int j = 0; j < arc_count; j++)
arc_delays[j] = 0.0;
}
edge->setArcDelays(arc_id);
// Make sure there is room for delay_annotated flags.
size_t max_annot_index = (arc_id + arc_count) * ap_count_;
if (max_annot_index >= arc_delay_annotated_.size()) {
size_t size = max_annot_index * 1.2;
arc_delay_annotated_.resize(size);
}
removeDelayAnnotated(edge);
}
}
ArcDelay
Graph::arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
if (have_arc_delays_) {
DelayTable *table = arc_delays_[ap_index];
ArcDelay *arc_delays = table->pointer(edge->arcDelays());
ArcDelay &arc_delay = arc_delays[arc->index()];
return arc_delay;
}
else
return delay_zero;
ArcDelay *delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
return delays[index];
}
void
@ -874,11 +749,9 @@ Graph::setArcDelay(Edge *edge,
DcalcAPIndex ap_index,
ArcDelay delay)
{
if (have_arc_delays_) {
DelayTable *table = arc_delays_[ap_index];
ArcDelay *arc_delays = table->pointer(edge->arcDelays());
arc_delays[arc->index()] = delay;
}
ArcDelay *arc_delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
arc_delays[index] = delay;
}
const ArcDelay &
@ -886,13 +759,9 @@ Graph::wireArcDelay(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index)
{
if (have_arc_delays_) {
DelayTable *table = arc_delays_[ap_index];
ArcDelay *arc_delays = table->pointer(edge->arcDelays());
return arc_delays[rf->index()];
}
else
return delay_zero;
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
return delays[index];
}
void
@ -901,26 +770,19 @@ Graph::setWireArcDelay(Edge *edge,
DcalcAPIndex ap_index,
const ArcDelay &delay)
{
if (have_arc_delays_) {
DelayTable *table = arc_delays_[ap_index];
ArcDelay *arc_delays = table->pointer(edge->arcDelays());
arc_delays[rf->index()] = delay;
}
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
delays[index] = delay;
}
////////////////////////////////////////////////////////////////
bool
Graph::arcDelayAnnotated(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
if (!arc_delay_annotated_.empty()) {
size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(1080, "arc_delay_annotated array bounds exceeded");
return arc_delay_annotated_[index];
}
else
return false;
return edge->arcDelayAnnotated(arc, ap_index, ap_count_);
}
void
@ -929,22 +791,17 @@ Graph::setArcDelayAnnotated(Edge *edge,
DcalcAPIndex ap_index,
bool annotated)
{
size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(1081, "arc_delay_annotated array bounds exceeded");
arc_delay_annotated_[index] = annotated;
return edge->setArcDelayAnnotated(arc, ap_index, ap_count_, annotated);
}
bool
Graph::wireDelayAnnotated(Edge *edge,
Graph::wireDelayAnnotated(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index) const
{
size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_
+ ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(1082, "arc_delay_annotated array bounds exceeded");
return arc_delay_annotated_[index];
int arc_index = TimingArcSet::wireArcIndex(rf);
TimingArc *arc = TimingArcSet::wireTimingArcSet()->findTimingArc(arc_index);
return edge->arcDelayAnnotated(arc, ap_index, ap_count_);
}
void
@ -953,13 +810,19 @@ Graph::setWireDelayAnnotated(Edge *edge,
DcalcAPIndex ap_index,
bool annotated)
{
size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_
+ ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(1083, "arc_delay_annotated array bounds exceeded");
arc_delay_annotated_[index] = annotated;
int arc_index = TimingArcSet::wireArcIndex(rf);
TimingArc *arc = TimingArcSet::wireTimingArcSet()->findTimingArc(arc_index);
return edge->setArcDelayAnnotated(arc, ap_index, ap_count_, annotated);
}
void
Graph::removeDelayAnnotated(Edge *edge)
{
edge->removeDelayAnnotated();
}
////////////////////////////////////////////////////////////////
// This only gets called if the analysis type changes from single
// to bc_wc/ocv or visa versa.
void
@ -967,42 +830,53 @@ Graph::setDelayCount(DcalcAPIndex ap_count)
{
if (ap_count != ap_count_) {
// Discard any existing delays.
deleteSlewTables();
deleteArcDelayTables();
removePeriodCheckAnnotations();
makeSlewTables(ap_count);
makeArcDelayTables(ap_count);
ap_count_ = ap_count;
removeDelays();
initSlews();
}
}
void
Graph::removeDelays()
Graph::initSlews()
{
VertexIterator vertex_iter(this);
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
makeVertexSlews(vertex);
VertexOutEdgeIterator edge_iter(vertex, this);
initSlews(vertex);
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
makeEdgeArcDelays(edge);
removeDelayAnnotated(edge);
initArcDelays(edge);
}
}
}
void
Graph::removeDelayAnnotated(Edge *edge)
Graph::initSlews(Vertex *vertex)
{
edge->setDelayAnnotationIsIncremental(false);
TimingArcSet *arc_set = edge->timingArcSet();
for (TimingArc *arc : arc_set->arcs()) {
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
setArcDelayAnnotated(edge, arc, ap_index, false);
}
}
size_t slew_count = slewCount();
Slew *slews = new Slew[slew_count];
vertex->setSlews(slews);
for (size_t i = 0; i < slew_count; i++)
slews[i] = 0.0;
}
size_t
Graph::slewCount()
{
return slew_rf_count_ * ap_count_;
}
void
Graph::initArcDelays(Edge *edge)
{
size_t arc_count = edge->timingArcSet()->arcCount();
size_t delay_count = arc_count * ap_count_;
ArcDelay *arc_delays = new ArcDelay[delay_count];
edge->setArcDelays(arc_delays);
for (size_t i = 0; i < delay_count; i++)
arc_delays[i] = 0.0;
}
bool
@ -1018,35 +892,6 @@ Graph::delayAnnotated(Edge *edge)
return true;
}
void
Graph::makeSlewTables(DcalcAPIndex ap_count)
{
DcalcAPIndex tr_ap_count = slew_rf_count_ * ap_count;
slew_tables_.resize(tr_ap_count);
for (DcalcAPIndex i = 0; i < tr_ap_count; i++) {
DelayTable *table = new DelayTable;
slew_tables_[i] = table;
}
}
void
Graph::deleteSlewTables()
{
slew_tables_.deleteContentsClear();
}
void
Graph::makeVertexSlews(Vertex *vertex)
{
DcalcAPIndex tr_ap_count = slew_rf_count_ * ap_count_;
for (DcalcAPIndex i = 0; i < tr_ap_count; i++) {
DelayTable *table = slew_tables_[i];
// Slews are 1:1 with vertices and use the same object id.
Slew *slew = table->ensureId(vertices_->objectId(vertex));
*slew = 0.0;
}
}
////////////////////////////////////////////////////////////////
void
@ -1161,9 +1006,10 @@ Vertex::init(Pin *pin,
is_bidirect_drvr_ = is_bidirect_drvr;
in_edges_ = edge_id_null;
out_edges_ = edge_id_null;
arrivals_ = arrival_null;
requireds_ = arrival_null;
prev_paths_ = prev_path_null;
slews_ = nullptr;
arrivals_ = nullptr;
requireds_ = nullptr;
prev_paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
slew_annotated_ = false;
sim_value_ = unsigned(LogicValue::unknown);
@ -1180,6 +1026,24 @@ Vertex::init(Pin *pin,
requireds_pruned_ = false;
}
Vertex::~Vertex()
{
clear();
}
void
Vertex::clear()
{
delete [] slews_;
slews_ = nullptr;
delete [] arrivals_;
arrivals_ = nullptr;
delete [] requireds_;
requireds_ = nullptr;
delete [] prev_paths_;
prev_paths_ = nullptr;
}
void
Vertex::setObjectIdx(ObjectIdx idx)
{
@ -1228,6 +1092,13 @@ Vertex::setColor(LevelColor color)
color_ = unsigned(color);
}
void
Vertex::setSlews(Slew *slews)
{
delete [] slews_;
slews_ = slews;
}
bool
Vertex::slewAnnotated(const RiseFall *rf,
const MinMax *min_max) const
@ -1289,20 +1160,23 @@ Vertex::setTagGroupIndex(TagGroupIndex tag_index)
}
void
Vertex::setArrivals(ArrivalId id)
Vertex::setArrivals(Arrival *arrivals)
{
arrivals_ = id;
delete [] arrivals_;
arrivals_ = arrivals;
}
void
Vertex::setRequireds(ArrivalId id)
Vertex::setRequireds(Required *requireds)
{
requireds_ = id;
delete [] requireds_;
requireds_ = requireds;
}
void
Vertex::setPrevPaths(PrevPathId prev_paths)
Vertex::setPrevPaths(PathVertexRep *prev_paths)
{
delete [] prev_paths_;
prev_paths_ = prev_paths;
}
@ -1410,13 +1284,15 @@ Edge::init(VertexId from,
from_ = from;
to_ = to;
arc_set_ = arc_set;
arc_delays_ = 0;
vertex_in_link_ = edge_id_null;
vertex_out_next_ = edge_id_null;
vertex_out_prev_ = edge_id_null;
is_bidirect_inst_path_ = false;
is_bidirect_net_path_ = false;
arc_delays_ = nullptr;
arc_delay_annotated_is_bits_ = true;
arc_delay_annotated_.bits_ = 0;
delay_annotation_is_incremental_ = false;
sim_timing_sense_ = unsigned(TimingSense::unknown);
is_disabled_constraint_ = false;
@ -1424,6 +1300,22 @@ Edge::init(VertexId from,
is_disabled_loop_ = false;
}
Edge::~Edge()
{
clear();
}
void
Edge::clear()
{
delete [] arc_delays_;
arc_delays_ = nullptr;
if (!arc_delay_annotated_is_bits_)
delete arc_delay_annotated_.seq_;
arc_delay_annotated_is_bits_ = true;
arc_delay_annotated_.seq_ = nullptr;
}
void
Edge::setObjectIdx(ObjectIdx idx)
{
@ -1437,15 +1329,56 @@ Edge::setTimingArcSet(TimingArcSet *set)
}
void
Edge::setArcDelays(ArcId arc_delays)
Edge::setArcDelays(ArcDelay *arc_delays)
{
delete [] arc_delays_;
arc_delays_ = arc_delays;
}
bool
Edge::delayAnnotationIsIncremental() const
Edge::arcDelayAnnotated(const TimingArc *arc,
DcalcAPIndex ap_index,
DcalcAPIndex ap_count) const
{
return delay_annotation_is_incremental_;
size_t index = arc->index() * ap_count + ap_index;
if (arc_delay_annotated_is_bits_)
return arc_delay_annotated_.bits_ & (1 << index);
else
return (*arc_delay_annotated_.seq_)[index];
}
void
Edge::setArcDelayAnnotated(const TimingArc *arc,
DcalcAPIndex ap_index,
DcalcAPIndex ap_count,
bool annotated)
{
size_t index = arc->index() * ap_count + ap_index;
if (index > sizeof(intptr_t) * 8
&& arc_delay_annotated_is_bits_) {
arc_delay_annotated_is_bits_ = false;
arc_delay_annotated_.seq_ = new vector<bool>(ap_count * RiseFall::index_count * 2);
}
if (arc_delay_annotated_is_bits_) {
if (annotated)
arc_delay_annotated_.bits_ |= (1 << index);
else
arc_delay_annotated_.bits_ &= ~(1 << index);
}
else
(*arc_delay_annotated_.seq_)[index] = annotated;
}
void
Edge::removeDelayAnnotated()
{
delay_annotation_is_incremental_ = false;
if (arc_delay_annotated_is_bits_)
arc_delay_annotated_.bits_ = 0;
else {
delete arc_delay_annotated_.seq_;
arc_delay_annotated_.seq_ = nullptr;
}
}
void

View File

@ -83,12 +83,6 @@ private:
%inline %{
int
graph_arc_count()
{
return Sta::sta()->ensureGraph()->arcCount();
}
VertexIterator *
vertex_iterator()
{

View File

@ -1,275 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <cstring> // memcpy
#include <vector>
#include <atomic>
#include "ObjectId.hh"
#include "Error.hh"
namespace sta {
template <class TYPE>
class ArrayBlock;
// Array tables allocate arrays of objects in blocks and use 32 bit IDs to
// reference the array. Paging performance is improved by allocating
// blocks instead of individual arrays, and object sizes are reduced
// by using 32 bit references instead of 64 bit pointers.
// They are similar to ObjectTables but do not support delete/destroy or
// reclaiming deleted arrays.
template <class TYPE>
class ArrayTable
{
public:
ArrayTable();
~ArrayTable();
void make(uint32_t count,
TYPE *&array,
ObjectId &id);
void destroy(ObjectId id,
uint32_t count);
// Grow as necessary and return pointer for id.
TYPE *ensureId(ObjectId id);
TYPE *pointer(ObjectId id) const;
TYPE &ref(ObjectId id) const;
size_t size() const { return size_; }
void clear();
static constexpr int idx_bits = 7;
static constexpr int block_size = (1 << idx_bits);
static constexpr int block_id_max = 1 << (object_id_bits - idx_bits);
private:
ArrayBlock<TYPE> *makeBlock(uint32_t size);
void pushBlock(ArrayBlock<TYPE> *block);
void deleteBlocks();
size_t size_;
// Block index of free block (blocks_[size - 1]).
BlockIdx free_block_idx_;
// Index of next free object in free_block_idx_.
ObjectIdx free_idx_;
// Don't use std::vector so growing blocks_ can be thread safe.
size_t blocks_size_;
size_t blocks_capacity_;
std::atomic<ArrayBlock<TYPE>**> blocks_;
// Linked list of free arrays indexed by array size.
std::vector<ObjectId> free_list_;
static constexpr ObjectId idx_mask_ = block_size - 1;
};
template <class TYPE>
ArrayTable<TYPE>::ArrayTable() :
size_(0),
free_block_idx_(block_idx_null),
free_idx_(object_idx_null),
blocks_size_(0),
blocks_capacity_(1024),
blocks_(new ArrayBlock<TYPE>*[blocks_capacity_])
{
}
template <class TYPE>
ArrayTable<TYPE>::~ArrayTable()
{
deleteBlocks();
delete [] blocks_;
}
template <class TYPE>
void
ArrayTable<TYPE>::deleteBlocks()
{
for (size_t i = 0; i < blocks_size_; i++)
delete blocks_[i];
}
template <class TYPE>
void
ArrayTable<TYPE>::make(uint32_t count,
TYPE *&array,
ObjectId &id)
{
// Check the free list for a previously destroyed array with the right size.
if (count < free_list_.size()
&& free_list_[count] != object_id_null) {
id = free_list_[count];
array = pointer(id);
ObjectId *head = reinterpret_cast<ObjectId*>(array);
free_list_[count] = *head;
}
else {
ArrayBlock<TYPE> *block = blocks_size_ ? blocks_[free_block_idx_] : nullptr;
if ((free_idx_ == object_idx_null
&& free_block_idx_ == block_idx_null)
|| free_idx_ + count >= block->size()) {
uint32_t size = block_size;
if (blocks_size_ == 0
// First block starts at idx 1.
&& count > block_size - 1)
size = count + 1;
else if (count > block_size)
size = count;
block = makeBlock(size);
}
// makeId(free_block_idx_, idx_bits)
id = (free_block_idx_ << idx_bits) + free_idx_;
array = block->pointer(free_idx_);
free_idx_ += count;
}
size_ += count;
}
template <class TYPE>
ArrayBlock<TYPE> *
ArrayTable<TYPE>::makeBlock(uint32_t size)
{
BlockIdx block_idx = blocks_size_;
ArrayBlock<TYPE> *block = new ArrayBlock<TYPE>(size);
pushBlock(block);
free_block_idx_ = block_idx;
// ObjectId zero is reserved for object_id_null.
free_idx_ = (block_idx > 0) ? 0 : 1;
return block;
}
template <class TYPE>
void
ArrayTable<TYPE>::pushBlock(ArrayBlock<TYPE> *block)
{
blocks_[blocks_size_++] = block;
if (blocks_size_ >= block_id_max)
criticalError(223, "max array table block count exceeded.");
if (blocks_size_ == blocks_capacity_) {
size_t new_capacity = blocks_capacity_ * 1.5;
ArrayBlock<TYPE>** new_blocks = new ArrayBlock<TYPE>*[new_capacity];
memcpy(new_blocks, blocks_, blocks_capacity_ * sizeof(ArrayBlock<TYPE>*));
blocks_ = new_blocks;
blocks_capacity_ = new_capacity;
}
}
template <class TYPE>
void
ArrayTable<TYPE>::destroy(ObjectId id,
uint32_t count)
{
if (count >= free_list_.size())
free_list_.resize(count + 1);
TYPE *array = pointer(id);
// Prepend id to the free list.
ObjectId *head = reinterpret_cast<ObjectId*>(array);
*head = free_list_[count];
free_list_[count] = id;
size_ -= count;
}
template <class TYPE>
TYPE *
ArrayTable<TYPE>::pointer(ObjectId id) const
{
if (id == object_id_null)
return nullptr;
else {
BlockIdx blk_idx = id >> idx_bits;
ObjectIdx obj_idx = id & idx_mask_;
return blocks_[blk_idx]->pointer(obj_idx);
}
}
template <class TYPE>
TYPE *
ArrayTable<TYPE>::ensureId(ObjectId id)
{
BlockIdx blk_idx = id >> idx_bits;
ObjectIdx obj_idx = id & idx_mask_;
// Make enough blocks for blk_idx to be valid.
for (BlockIdx i = blocks_size_; i <= blk_idx; i++) {
ArrayBlock<TYPE> *block = new ArrayBlock<TYPE>(block_size);
pushBlock(block);
}
return blocks_[blk_idx]->pointer(obj_idx);
}
template <class TYPE>
TYPE &
ArrayTable<TYPE>::ref(ObjectId id) const
{
if (id == object_id_null)
criticalError(222, "null ObjectId reference is undefined.");
BlockIdx blk_idx = id >> idx_bits;
ObjectIdx obj_idx = id & idx_mask_;
return blocks_[blk_idx]->ref(obj_idx);
}
template <class TYPE>
void
ArrayTable<TYPE>::clear()
{
deleteBlocks();
blocks_size_ = 0;
size_ = 0;
free_block_idx_ = block_idx_null;
free_idx_ = object_idx_null;
free_list_.clear();
}
////////////////////////////////////////////////////////////////
template <class TYPE>
class ArrayBlock
{
public:
ArrayBlock(uint32_t size);
~ArrayBlock();
uint32_t size() const { return size_; }
TYPE &ref(ObjectIdx idx) { return objects_[idx]; }
TYPE *pointer(ObjectIdx idx) { return &objects_[idx]; }
private:
uint32_t size_;
TYPE *objects_;
};
template <class TYPE>
ArrayBlock<TYPE>::ArrayBlock(uint32_t size) :
size_(size),
objects_(new TYPE[size])
{
}
template <class TYPE>
ArrayBlock<TYPE>::~ArrayBlock()
{
delete [] objects_;
}
} // Namespace

View File

@ -31,7 +31,6 @@
#include "Map.hh"
#include "Vector.hh"
#include "ObjectTable.hh"
#include "ArrayTable.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
#include "Delay.hh"
@ -47,25 +46,16 @@ class Sdc;
enum class LevelColor { white, gray, black };
typedef ArrayTable<Delay> DelayTable;
typedef ObjectTable<Vertex> VertexTable;
typedef ObjectTable<Edge> EdgeTable;
typedef ArrayTable<Arrival> ArrivalsTable;
typedef ArrayTable<Required> RequiredsTable;
typedef ArrayTable<PathVertexRep> PrevPathsTable;
typedef Map<const Pin*, Vertex*> PinVertexMap;
typedef Iterator<Edge*> VertexEdgeIterator;
typedef Map<const Pin*, float*, PinIdLess> PeriodCheckAnnotations;
typedef Vector<DelayTable*> DelayTableSeq;
typedef ObjectId EdgeId;
typedef ObjectId ArrivalId;
typedef ObjectId PrevPathId;
static constexpr EdgeId edge_id_null = object_id_null;
static constexpr ObjectIdx edge_idx_null = object_id_null;
static constexpr ObjectIdx vertex_idx_null = object_id_null;
static constexpr ObjectIdx arrival_null = object_id_null;
static constexpr ObjectIdx prev_path_null = object_id_null;
// The graph acts as a BUILDER for the graph vertices and edges.
class Graph : public StaState
@ -78,17 +68,17 @@ public:
// ap_count is the dcalc analysis point count.
Graph(StaState *sta,
int slew_rf_count,
bool have_arc_delays,
DcalcAPIndex ap_count);
void makeGraph();
virtual ~Graph();
~Graph();
// Number of arc delays and slews from sdf or delay calculation.
virtual void setDelayCount(DcalcAPIndex ap_count);
void setDelayCount(DcalcAPIndex ap_count);
size_t slewCount();
// Vertex functions.
// Bidirect pins have two vertices.
virtual Vertex *vertex(VertexId vertex_id) const;
Vertex *vertex(VertexId vertex_id) const;
VertexId id(const Vertex *vertex) const;
void makePinVertices(Pin *pin);
void makePinVertices(Pin *pin,
@ -103,56 +93,49 @@ public:
Vertex *pinDrvrVertex(const Pin *pin) const;
// Load vertex for bidirects.
Vertex *pinLoadVertex(const Pin *pin) const;
virtual void deleteVertex(Vertex *vertex);
void deleteVertex(Vertex *vertex);
bool hasFaninOne(Vertex *vertex) const;
VertexId vertexCount() { return vertices_->size(); }
Arrival *makeArrivals(Vertex *vertex,
uint32_t count);
Arrival *arrivals(Vertex *vertex);
void deleteArrivals(Vertex *vertex,
uint32_t count);
Arrival *arrivals(const Vertex *vertex) const;
void deleteArrivals(Vertex *vertex);
Required *makeRequireds(Vertex *vertex,
uint32_t count);
Required *requireds(Vertex *vertex);
void deleteRequireds(Vertex *vertex,
uint32_t count);
Required *requireds(const Vertex *vertex) const;
void deleteRequireds(Vertex *vertex);
PathVertexRep *makePrevPaths(Vertex *vertex,
uint32_t count);
PathVertexRep *prevPaths(Vertex *vertex) const;
void deletePrevPaths(Vertex *vertex,
uint32_t count);
// Private to Search::deletePaths().
void deletePaths();
PathVertexRep *prevPaths(const Vertex *vertex) const;
void deletePrevPaths(Vertex *vertex);
// Private to Search::deletePaths(Vertex).
void deletePaths(Vertex *vertex,
uint32_t count);
void deletePaths(Vertex *vertex);
// Reported slew are the same as those in the liberty tables.
// reported_slews = measured_slews / slew_derate_from_library
// Measured slews are between slew_lower_threshold and slew_upper_threshold.
virtual const Slew &slew(const Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index);
virtual void setSlew(Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index,
const Slew &slew);
SlewSeq slews(Vertex *vertex);
const Slew &slew(const Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index);
void setSlew(Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index,
const Slew &slew);
// Edge functions.
virtual Edge *edge(EdgeId edge_index) const;
Edge *edge(EdgeId edge_index) const;
EdgeId id(const Edge *edge) const;
virtual Edge *makeEdge(Vertex *from,
Vertex *to,
TimingArcSet *arc_set);
virtual void makeWireEdge(const Pin *from_pin,
const Pin *to_pin);
Edge *makeEdge(Vertex *from,
Vertex *to,
TimingArcSet *arc_set);
void makeWireEdge(const Pin *from_pin,
const Pin *to_pin);
void makePinInstanceEdges(const Pin *pin);
void makeInstanceEdges(const Instance *inst);
void makeWireEdgesToPin(const Pin *to_pin);
void makeWireEdgesThruPin(const Pin *hpin);
virtual void makeWireEdgesFromPin(const Pin *drvr_pin);
virtual void deleteEdge(Edge *edge);
void makeWireEdgesFromPin(const Pin *drvr_pin);
void deleteEdge(Edge *edge);
// Find the edge and timing arc on a gate between in_pin and drvr_pin.
void gateEdgeArc(const Pin *in_pin,
const RiseFall *in_rf,
@ -162,21 +145,21 @@ public:
Edge *&edge,
const TimingArc *&arc) const;
virtual ArcDelay arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
virtual void setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay);
ArcDelay arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
void setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay);
// Alias for arcDelays using library wire arcs.
virtual const ArcDelay &wireArcDelay(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index);
virtual void setWireArcDelay(Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index,
const ArcDelay &delay);
const ArcDelay &wireArcDelay(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index);
void setWireArcDelay(Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index,
const ArcDelay &delay);
// Is timing arc delay annotated.
bool arcDelayAnnotated(const Edge *edge,
const TimingArc *arc,
@ -185,7 +168,7 @@ public:
const TimingArc *arc,
DcalcAPIndex ap_index,
bool annotated);
bool wireDelayAnnotated(Edge *edge,
bool wireDelayAnnotated(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index) const;
void setWireDelayAnnotated(Edge *edge,
@ -194,8 +177,6 @@ public:
bool annotated);
// True if any edge arc is annotated.
bool delayAnnotated(Edge *edge);
int edgeCount() { return edges_->size(); }
virtual int arcCount() { return arc_count_; }
void minPulseWidthArc(Vertex *vertex,
const RiseFall *hi_low,
@ -211,6 +192,7 @@ public:
void setPeriodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
float period);
// Remove all delay and slew annotations.
void removeDelaySlewAnnotations();
VertexSet *regClkVertices() { return reg_clk_vertices_; }
@ -223,29 +205,27 @@ protected:
Vertex *makeVertex(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk);
virtual void makeEdgeArcDelays(Edge *edge);
void makeEdgeArcDelays(Edge *edge);
void makePinVertices(const Instance *inst);
void makeWireEdgesFromPin(const Pin *drvr_pin,
PinSet &visited_drvrs);
bool isIsolatedNet(PinSeq &drvrs,
PinSeq &loads) const;
void makeWireEdges();
virtual void makeInstDrvrWireEdges(const Instance *inst,
PinSet &visited_drvrs);
virtual void makePortInstanceEdges(const Instance *inst,
LibertyCell *cell,
LibertyPort *from_to_port);
void makeInstDrvrWireEdges(const Instance *inst,
PinSet &visited_drvrs);
void makePortInstanceEdges(const Instance *inst,
LibertyCell *cell,
LibertyPort *from_to_port);
void removePeriodCheckAnnotations();
void makeSlewTables(DcalcAPIndex count);
void deleteSlewTables();
void makeVertexSlews(Vertex *vertex);
void makeArcDelayTables(DcalcAPIndex ap_count);
void deleteArcDelayTables();
void deleteInEdge(Vertex *vertex,
Edge *edge);
void deleteOutEdge(Vertex *vertex,
Edge *edge);
void removeDelays();
void initSlews();
void initSlews(Vertex *vertex);
void initArcDelays(Edge *edge);
void removeDelayAnnotated(Edge *edge);
VertexTable *vertices_;
@ -255,20 +235,8 @@ protected:
// driver/source (top level input, instance pin output) vertex
// in pin_bidirect_drvr_vertex_map
PinVertexMap pin_bidirect_drvr_vertex_map_;
int arc_count_;
ArrivalsTable arrivals_;
std::mutex arrivals_lock_;
RequiredsTable requireds_;
std::mutex requireds_lock_;
PrevPathsTable prev_paths_;
std::mutex prev_paths_lock_;
Vector<bool> arc_delay_annotated_;
int slew_rf_count_;
bool have_arc_delays_;
DcalcAPIndex ap_count_;
DelayTableSeq slew_tables_; // [ap_index][tr_index][vertex_id]
VertexId slew_count_;
DelayTableSeq arc_delays_; // [ap_index][edge_arc_index]
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
// Register/latch clock vertices to search from.
@ -286,6 +254,7 @@ class Vertex
{
public:
Vertex();
~Vertex();
Pin *pin() const { return pin_; }
// Pin path with load/driver suffix for bidirects.
const char *name(const Network *network) const;
@ -298,11 +267,12 @@ public:
bool hasFanout() const;
LevelColor color() const { return static_cast<LevelColor>(color_); }
void setColor(LevelColor color);
ArrivalId arrivals() { return arrivals_; }
ArrivalId requireds() { return requireds_; }
bool hasRequireds() const { return requireds_ != arrival_null; }
PrevPathId prevPaths() const { return prev_paths_; }
void setPrevPaths(PrevPathId id);
Slew *slews() { return slews_; }
const Slew *slews() const { return slews_; }
Arrival *arrivals() const { return arrivals_; }
Arrival *requireds() const { return requireds_; }
PathVertexRep *prevPaths() const { return prev_paths_; }
void setPrevPaths(PathVertexRep *prev_paths);
TagGroupIndex tagGroupIndex() const;
void setTagGroupIndex(TagGroupIndex tag_index);
// Slew is annotated by sdc set_annotated_transition cmd.
@ -341,6 +311,7 @@ public:
bool isRegClk() const { return is_reg_clk_; }
bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;}
void setCrprPathPruningDisabled(bool disabled);
bool hasRequireds() const { return requireds_ != nullptr; }
bool requiredsPruned() const { return requireds_pruned_; }
void setRequiredsPruned(bool pruned);
@ -354,22 +325,30 @@ protected:
void init(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk);
void setArrivals(ArrivalId id);
void setRequireds(ArrivalId id);
void clear();
void setArrivals(Arrival *arrivals);
void setRequireds(Required *requireds);
void setSlews(Slew *slews);
Pin *pin_;
ArrivalId arrivals_;
ArrivalId requireds_;
PrevPathId prev_paths_;
EdgeId in_edges_; // Edges to this vertex.
EdgeId out_edges_; // Edges from this vertex.
// 28 bits
unsigned int tag_group_index_:tag_group_index_bits; // 24
unsigned int slew_annotated_:slew_annotated_bits; // 4
// Delay calc
Slew *slews_;
// Search
Arrival *arrivals_;
Arrival *requireds_;
PathVertexRep *prev_paths_;
// These fields are written by multiple threads, so they
// cannot share the same word as the following bit fields.
uint32_t tag_group_index_;
// Each bit corresponds to a different BFS queue.
std::atomic<uint8_t> bfs_in_queue_; // 4
// 32 bits
unsigned int level_:Graph::vertex_level_bits; // 24
unsigned int slew_annotated_:slew_annotated_bits; // 4
// Levelization search state.
// LevelColor gcc barfs if this is dcl'd.
unsigned color_:2;
@ -379,11 +358,6 @@ protected:
// This flag distinguishes the driver and load vertices.
bool is_bidirect_drvr_:1;
bool is_reg_clk_:1;
// Each bit corresponds to a different BFS queue.
std::atomic<uint8_t> bfs_in_queue_; // 4
// 15 bits
bool is_disabled_constraint_:1;
bool is_gated_clk_enable_:1;
// Constrained by timing check edge.
@ -409,6 +383,7 @@ class Edge
{
public:
Edge();
~Edge();
Vertex *to(const Graph *graph) const { return graph->vertex(to_); }
Vertex *from(const Graph *graph) const { return graph->vertex(from_); }
TimingRole *role() const;
@ -416,9 +391,9 @@ public:
TimingSense sense() const;
TimingArcSet *timingArcSet() const { return arc_set_; }
void setTimingArcSet(TimingArcSet *set);
ArcId arcDelays() const { return arc_delays_; }
void setArcDelays(ArcId arc_delays);
bool delayAnnotationIsIncremental() const;
ArcDelay *arcDelays() const { return arc_delays_; }
void setArcDelays(ArcDelay *arc_delays);
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
void setDelayAnnotationIsIncremental(bool is_incr);
// Edge is disabled by set_disable_timing constraint.
bool isDisabledConstraint() const;
@ -438,6 +413,7 @@ public:
void setIsBidirectInstPath(bool is_bidir);
bool isBidirectNetPath() const { return is_bidirect_net_path_; }
void setIsBidirectNetPath(bool is_bidir);
void removeDelayAnnotated();
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
@ -447,6 +423,14 @@ protected:
void init(VertexId from,
VertexId to,
TimingArcSet *arc_set);
void clear();
bool arcDelayAnnotated(const TimingArc *arc,
DcalcAPIndex ap_index,
DcalcAPIndex ap_count) const;
void setArcDelayAnnotated(const TimingArc *arc,
DcalcAPIndex ap_index,
DcalcAPIndex ap_count,
bool annotated);
TimingArcSet *arc_set_;
VertexId from_;
@ -454,8 +438,12 @@ protected:
EdgeId vertex_in_link_; // Vertex in edges list.
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
EdgeId vertex_out_prev_;
ArcId arc_delays_;
// 16 bits
ArcDelay *arc_delays_;
union {
uintptr_t bits_;
vector<bool> *seq_;
} arc_delay_annotated_;
bool arc_delay_annotated_is_bits_:1;
bool delay_annotation_is_incremental_:1;
bool is_bidirect_inst_path_:1;
bool is_bidirect_net_path_:1;

View File

@ -49,7 +49,6 @@ class VertexSet;
typedef ObjectId VertexId;
typedef ObjectId EdgeId;
typedef ObjectId ArcId;
typedef Vector<Vertex*> VertexSeq;
typedef Vector<Edge*> EdgeSeq;
typedef Set<Edge*> EdgeSet;

View File

@ -210,8 +210,8 @@ public:
virtual bool isTopInstance(const Instance *inst) const;
virtual Instance *findInstance(const char *path_name) const;
// Find instance relative to hierarchical instance.
Instance *findInstanceRelative(const Instance *inst,
const char *path_name) const;
virtual Instance *findInstanceRelative(const Instance *inst,
const char *path_name) const;
// Default implementation uses linear search.
virtual InstanceSeq findInstancesMatching(const Instance *context,
const PatternMatch *pattern) const;
@ -363,8 +363,8 @@ public:
virtual ObjectId id(const Net *net) const = 0;
virtual Net *findNet(const char *path_name) const;
// Find net relative to hierarchical instance.
Net *findNetRelative(const Instance *inst,
const char *path_name) const;
virtual Net *findNetRelative(const Instance *inst,
const char *path_name) const;
// Default implementation uses linear search.
virtual NetSeq findNetsMatching(const Instance *context,
const PatternMatch *pattern) const;

View File

@ -173,7 +173,6 @@ void
ObjectTable<TYPE>::destroy(TYPE *object)
{
ObjectId object_id = objectId(object);
object->~TYPE();
size_--;
freePush(object, object_id);
}

View File

@ -208,9 +208,13 @@ public:
const char *pathName(const Net *net) const override;
Instance *findInstance(const char *path_name) const override;
Instance *findInstanceRelative(const Instance *inst,
const char *path_name) const override;
InstanceSeq findInstancesMatching(const Instance *context,
const PatternMatch *pattern) const override;
Net *findNet(const char *path_name) const override;
Net *findNetRelative(const Instance *instance,
const char *net_name) const override;
Net *findNet(const Instance *instance,
const char *net_name) const override;
NetSeq findNetsMatching(const Instance *parent,

View File

@ -383,7 +383,8 @@ protected:
bool report_max,
DcalcAnalysisPt *dcalc_ap_min,
DcalcAnalysisPt *dcalc_ap_max);
virtual void deleteTags();
void deleteTags();
void deleteTagsPrev();
void seedInvalidArrivals();
void seedArrivals();
void findClockVertices(VertexSet &vertices);
@ -593,12 +594,14 @@ protected:
// Entries in tags_ may be missing where previous filter tags were deleted.
TagIndex tag_capacity_;
std::atomic<Tag **> tags_;
vector<Tag **> tags_prev_;
TagIndex tag_next_;
// Holes in tags_ left by deleting filter tags.
std::vector<TagIndex> tag_free_indices_;
std::mutex tag_lock_;
TagGroupSet *tag_group_set_;
std::atomic<TagGroup **> tag_groups_;
vector<TagGroup **> tag_groups_prev_;
TagGroupIndex tag_group_next_;
// Holes in tag_groups_ left by deleting filter tag groups.
std::vector<TagIndex> tag_group_free_indices_;

View File

@ -789,6 +789,22 @@ SdcNetwork::findInstance(const char *path_name) const
return child;
}
Instance *
SdcNetwork::findInstanceRelative(const Instance *inst,
const char *path_name) const
{
Instance *inst1 = network_->findInstanceRelative(inst, path_name);
if (inst1 == nullptr) {
string path_name1 = escapeBrackets(path_name, this);
inst1 = network_->findInstanceRelative(inst, path_name1.c_str());
if (inst1 == nullptr) {
string path_name2 = escapeDividers(path_name1.c_str(), network_);
inst1 = network_->findInstanceRelative(inst, path_name2.c_str());
}
}
return inst1;
}
InstanceSeq
SdcNetwork::findInstancesMatching(const Instance *context,
const PatternMatch *pattern) const
@ -835,17 +851,34 @@ SdcNetwork::findNet(const char *path_name) const
parsePath(path_name, inst, net_name);
if (inst == nullptr)
inst = network_->topInstance();
return findNet(inst, net_name);
return findNetRelative(inst, net_name);
}
Net *
SdcNetwork::findNet(const Instance *instance,
const char *net_name) const
const char *net_name) const
{
Net *net = network_->findNet(instance, net_name);
if (net == nullptr) {
string net_name1 = escapeBrackets(net_name, this);
net = network_->findNet(instance, net_name1.c_str());
string net_name2 = escapeDividers(net_name1.c_str(), network_);
net = network_->findNet(instance, net_name2.c_str());
}
return net;
}
Net *
SdcNetwork::findNetRelative(const Instance *inst,
const char *path_name) const
{
Net *net = network_->findNetRelative(inst, path_name);
if (net == nullptr) {
string path_name1 = escapeBrackets(path_name, this);
net = network_->findNetRelative(inst, path_name1.c_str());
if (net == nullptr) {
string path_name2 = escapeDividers(path_name1.c_str(), network_);
net = network_->findNetRelative(inst, path_name2.c_str());
}
}
return net;
}

View File

@ -51,7 +51,7 @@ typedef sta::SpefParse::token token;
%option never-interactive
%option stack
%option yylineno
/* %option debug */
%option debug
%x COMMENT
%x QUOTE

View File

@ -287,9 +287,7 @@ name_map_entries:
name_map_entry:
INDEX mapped_item
{ reader->makeNameMapEntry($1, $2);
sta::stringDelete($1);
}
{ reader->makeNameMapEntry($1, $2); }
;
mapped_item:

View File

@ -106,9 +106,6 @@ SpefReader::~SpefReader()
delete design_flow_;
design_flow_ = nullptr;
}
for (const auto [index, name] : name_map_)
stringDelete(name);
}
bool
@ -121,6 +118,7 @@ SpefReader::read()
SpefScanner scanner(&stream, filename_, this, report_);
scanner_ = &scanner;
SpefParse parser(&scanner, this);
//parser.set_debug_level(1);
// yyparse returns 0 on success.
success = (parser.parse() == 0);
stats.report("Read spef");
@ -160,7 +158,7 @@ SpefReader::setBusBrackets(char left,
Instance *
SpefReader::findInstanceRelative(const char *name)
{
return network_->findInstanceRelative(instance_, name);
return sdc_network_->findInstanceRelative(instance_, name);
}
Net *
@ -257,21 +255,23 @@ SpefReader::setInductScale(float scale,
}
void
SpefReader::makeNameMapEntry(char *index,
char *name)
SpefReader::makeNameMapEntry(const char *index,
const char *name)
{
int i = atoi(index + 1);
name_map_[i] = name;
stringDelete(index);
stringDelete(name);
}
char *
SpefReader::nameMapLookup(char *name)
const char *
SpefReader::nameMapLookup(const char *name)
{
if (name && name[0] == '*') {
int index = atoi(name + 1);
auto itr = name_map_.find(index);
const auto &itr = name_map_.find(index);
if (itr != name_map_.end())
return itr->second;
return itr->second.c_str();
else {
warn(1645, "no name map entry for %d.", index);
return nullptr;
@ -310,19 +310,19 @@ SpefReader::findPin(char *name)
char *delim = strrchr(name, delimiter_);
if (delim) {
*delim = '\0';
name = nameMapLookup(name);
if (name) {
Instance *inst = findInstanceRelative(name);
const char *name1 = nameMapLookup(name);
if (name1) {
Instance *inst = findInstanceRelative(name1);
// Replace delimiter for error messages.
*delim = delimiter_;
const char *port_name = delim + 1;
if (inst) {
pin = network_->findPin(inst, port_name);
if (pin == nullptr)
warn(1647, "pin %s not found.", name);
warn(1647, "pin %s not found.", name1);
}
else
warn(1648, "instance %s not found.", name);
warn(1648, "instance %s not found.", name1);
}
}
else {
@ -335,14 +335,14 @@ SpefReader::findPin(char *name)
}
Net *
SpefReader::findNet(char *name)
SpefReader::findNet(const char *name)
{
Net *net = nullptr;
name = nameMapLookup(name);
if (name) {
net = findNetRelative(name);
const char *name1 = nameMapLookup(name);
if (name1) {
net = findNetRelative(name1);
if (net == nullptr)
warn(1650, "net %s not found.", name);
warn(1650, "net %s not found.", name1);
}
return net;
}
@ -447,26 +447,26 @@ SpefReader::findParasiticNode(char *name,
if (delim) {
*delim = '\0';
char *name2 = delim + 1;
name = nameMapLookup(name);
if (name) {
Instance *inst = findInstanceRelative(name);
const char *name1 = nameMapLookup(name);
if (name1) {
Instance *inst = findInstanceRelative(name1);
if (inst) {
// <instance>:<port>
Pin *pin = network_->findPin(inst, name2);
if (pin) {
if (local_only
&& !network_->isConnected(net_, pin))
warn(1651, "%s not connected to net %s.", name, network_->pathName(net_));
warn(1651, "%s not connected to net %s.", name1, network_->pathName(net_));
return parasitics_->ensureParasiticNode(parasitic_, pin, network_);
}
else {
// Replace delimiter for error message.
*delim = delimiter_;
warn(1652, "pin %s not found.", name);
warn(1652, "pin %s not found.", name1);
}
}
else {
Net *net = findNet(name);
Net *net = findNet(name1);
// Replace delimiter for error messages.
*delim = delimiter_;
if (net) {
@ -477,25 +477,29 @@ SpefReader::findParasiticNode(char *name,
if (local_only
&& !network_->isConnected(net, net_))
warn(1653, "%s not connected to net %s.",
name,
name1,
network_->pathName(net_));
return parasitics_->ensureParasiticNode(parasitic_, net, id, network_);
}
else
warn(1654, "node %s not a pin or net:number", name);
warn(1654, "node %s not a pin or net:number", name1);
}
}
}
}
else {
// <top_level_port>
name = nameMapLookup(name);
Pin *pin = findPortPinRelative(name);
if (pin) {
if (local_only
&& !network_->isConnected(net_, pin))
warn(1655, "%s not connected to net %s.", name, network_->pathName(net_));
return parasitics_->ensureParasiticNode(parasitic_, pin, network_);
const char *name1 = nameMapLookup(name);
if (name1) {
Pin *pin = findPortPinRelative(name1);
if (pin) {
if (local_only
&& !network_->isConnected(net_, pin))
warn(1655, "%s not connected to net %s.", name1, network_->pathName(net_));
return parasitics_->ensureParasiticNode(parasitic_, pin, network_);
}
else
warn(1656, "pin %s not found.", name1);
}
else
warn(1656, "pin %s not found.", name);

View File

@ -41,7 +41,9 @@ class SpefTriple;
class Corner;
class SpefScanner;
typedef std::map<int, char*, std::less<int>> SpefNameMap;
using std::string;
typedef std::map<int, string> SpefNameMap;
class SpefReader : public StaState
{
@ -79,12 +81,12 @@ public:
const char *units);
void setInductScale(float scale,
const char *units);
void makeNameMapEntry(char *index,
char *name);
char *nameMapLookup(char *index);
void makeNameMapEntry(const char *index,
const char *name);
const char *nameMapLookup(const char *index);
void setDesignFlow(StringSeq *flow_keys);
Pin *findPin(char *name);
Net *findNet(char *name);
Net *findNet(const char *name);
void rspfBegin(Net *net,
SpefTriple *total_cap);
void rspfFinish();

View File

@ -269,7 +269,6 @@ proc check_unit { unit key suffix key_var } {
if { [string match -nocase $arg_suffix $suffix] } {
set arg_prefix [string range $value 0 end-$suffix_length]
if { [regexp "^(10*)?(\[Mkmunpf\])?$" $arg_prefix ignore mult prefix] } {
#puts "$arg_prefix '$mult' '$prefix'"
if { $mult == "" } {
set mult 1
}

View File

@ -368,6 +368,7 @@ Search::deleteTags()
tag_free_indices_.clear();
clk_info_set_->deleteContentsClear();
deleteTagsPrev();
}
void
@ -408,7 +409,11 @@ Search::deletePaths()
{
debugPrint(debug_, "search", 1, "delete paths");
if (arrivals_exist_) {
graph_->deletePaths();
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
deletePaths(vertex);
}
filtered_arrivals_->clear();
arrivals_exist_ = false;
}
@ -428,10 +433,8 @@ void
Search::deletePaths(Vertex *vertex)
{
TagGroup *tag_group = tagGroup(vertex);
if (tag_group) {
int arrival_count = tag_group->arrivalCount();
graph_->deletePaths(vertex, arrival_count);
}
if (tag_group)
graph_->deletePaths(vertex);
}
////////////////////////////////////////////////////////////////
@ -613,11 +616,25 @@ Search::findFilteredArrivals(bool thru_latches)
debugPrint(debug_, "search", 1, "find arrivals pass %d", pass);
int arrival_count = arrival_iter_->visitParallel(max_level,
arrival_visitor_);
deleteTagsPrev();
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
}
arrivals_exist_ = true;
}
// Delete stale tag arrarys.
void
Search::deleteTagsPrev()
{
for (Tag** tags: tags_prev_)
delete [] tags;
tags_prev_.clear();
for (TagGroup** tag_groups: tag_groups_prev_)
delete [] tag_groups;
tag_groups_prev_.clear();
}
VertexSeq
Search::filteredEndpoints()
{
@ -853,6 +870,7 @@ Search::findClkArrivals()
ClkArrivalSearchPred search_clk(this);
arrival_visitor_->init(false, &search_clk);
arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_);
deleteTagsPrev();
arrivals_exist_ = true;
stats.report("Find clk arrivals");
}
@ -1023,6 +1041,7 @@ Search::findArrivals1(Level level)
findArrivalsSeed();
Stats stats(debug_, report_);
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
deleteTagsPrev();
stats.report("Find arrivals");
if (arrival_iter_->empty()
&& invalid_arrivals_->empty()) {
@ -2671,6 +2690,7 @@ Search::findTagGroup(TagGroupBldr *tag_bldr)
TagGroup **tag_groups = new TagGroup*[tag_capacity];
memcpy(tag_groups, tag_groups_,
tag_group_capacity_ * sizeof(TagGroup*));
tag_groups_prev_.push_back(tag_groups_);
tag_groups_ = tag_groups;
tag_group_capacity_ = tag_capacity;
tag_group_set_->reserve(tag_capacity);
@ -2705,7 +2725,7 @@ Search::setVertexArrivals(Vertex *vertex,
else {
// Prev paths not required.
prev_paths = nullptr;
graph_->deletePrevPaths(vertex, arrival_count);
graph_->deletePrevPaths(vertex);
}
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
vertex->setTagGroupIndex(tag_group->index());
@ -2718,16 +2738,15 @@ Search::setVertexArrivals(Vertex *vertex,
requiredInvalid(vertex);
if (tag_group != prev_tag_group)
// Requireds can only be reused if the tag group is unchanged.
graph_->deleteRequireds(vertex, prev_tag_group->arrivalCount());
graph_->deleteRequireds(vertex);
}
}
else {
if (prev_tag_group) {
uint32_t prev_arrival_count = prev_tag_group->arrivalCount();
graph_->deleteArrivals(vertex, prev_arrival_count);
graph_->deleteArrivals(vertex);
if (has_requireds) {
requiredInvalid(vertex);
graph_->deleteRequireds(vertex, prev_arrival_count);
graph_->deleteRequireds(vertex);
}
}
Arrival *arrivals = graph_->makeArrivals(vertex, arrival_count);
@ -2907,6 +2926,7 @@ Search::findTag(const RiseFall *rf,
TagIndex tag_capacity = tag_capacity_ * 2;
Tag **tags = new Tag*[tag_capacity];
memcpy(tags, tags_, tag_capacity_ * sizeof(Tag*));
tags_prev_.push_back(tags_);
tags_ = tags;
tag_capacity_ = tag_capacity;
tag_set_->reserve(tag_capacity);
@ -3151,6 +3171,7 @@ Search::findRequireds(Level level)
seedRequireds();
seedInvalidRequireds();
int required_count = required_iter_->visitParallel(level, &req_visitor);
deleteTagsPrev();
requireds_exist_ = true;
debugPrint(debug_, "search", 1, "found %d requireds", required_count);
stats.report("Find requireds");
@ -3436,8 +3457,7 @@ RequiredCmp::requiredsSave(Vertex *vertex,
if (tag_group == nullptr)
requireds_changed = true;
else {
int arrival_count = tag_group->arrivalCount();
graph->deleteRequireds(vertex, arrival_count);
graph->deleteRequireds(vertex);
requireds_changed = true;
}
}

View File

@ -792,7 +792,7 @@ proc_redirect report_pulse_width_checks {
define_cmd_args "report_path" \
{[-min|-max]\
[-format full|full_clock|full_clock_expanded|short|end|summary]\
[-fields [capacitance|slew|input_pin|net]\
[-fields capacitance|slew|input_pin|net|src_attr]\
[-digits digits] [-no_line_splits]\
[> filename] [>> filename]\
pin ^|r|rise|v|f|fall}

View File

@ -3475,7 +3475,7 @@ Sta::ensureGraph()
void
Sta::makeGraph()
{
graph_ = new Graph(this, 2, true, corners_->dcalcAnalysisPtCount());
graph_ = new Graph(this, 2, corners_->dcalcAnalysisPtCount());
graph_->makeGraph();
}