384 lines
9.0 KiB
C++
384 lines
9.0 KiB
C++
// OpenSTA, Static Timing Analyzer
|
|
// Copyright (c) 2019, 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/>.
|
|
|
|
#include "Machine.hh"
|
|
#include "Report.hh"
|
|
#include "Debug.hh"
|
|
#include "Graph.hh"
|
|
#include "PathAnalysisPt.hh"
|
|
#include "ClkInfo.hh"
|
|
#include "Tag.hh"
|
|
#include "Corner.hh"
|
|
#include "Search.hh"
|
|
#include "PathVertexRep.hh"
|
|
#include "TagGroup.hh"
|
|
|
|
namespace sta {
|
|
|
|
TagGroup::TagGroup(TagGroupIndex index,
|
|
ArrivalMap *arrival_map,
|
|
bool has_clk_tag,
|
|
bool has_genclk_src_tag,
|
|
bool has_filter_tag,
|
|
bool has_loop_tag) :
|
|
arrival_map_(arrival_map),
|
|
hash_(arrivalMapHash(arrival_map_)),
|
|
index_(index),
|
|
has_clk_tag_(has_clk_tag),
|
|
has_genclk_src_tag_(has_genclk_src_tag),
|
|
has_filter_tag_(has_filter_tag),
|
|
has_loop_tag_(has_loop_tag),
|
|
own_arrival_map_(true)
|
|
{
|
|
}
|
|
|
|
TagGroup::TagGroup(TagGroupBldr *tag_bldr) :
|
|
arrival_map_(tag_bldr->arrivalMap()),
|
|
hash_(arrivalMapHash(arrival_map_)),
|
|
own_arrival_map_(false)
|
|
{
|
|
}
|
|
|
|
TagGroup::~TagGroup()
|
|
{
|
|
if (own_arrival_map_)
|
|
delete arrival_map_;
|
|
}
|
|
|
|
size_t
|
|
TagGroup::arrivalMapHash(ArrivalMap *arrival_map)
|
|
{
|
|
size_t hash = 0;
|
|
ArrivalMap::Iterator arrival_iter(arrival_map);
|
|
while (arrival_iter.hasNext()) {
|
|
Tag *tag;
|
|
int arrival_index;
|
|
arrival_iter.next(tag, arrival_index);
|
|
hash += tag->hash();
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
bool
|
|
TagGroup::hasTag(Tag *tag) const
|
|
{
|
|
return arrival_map_->hasKey(tag);
|
|
}
|
|
|
|
void
|
|
TagGroup::arrivalIndex(Tag *tag,
|
|
int &arrival_index,
|
|
bool &exists) const
|
|
{
|
|
arrival_map_->findKey(tag, arrival_index, exists);
|
|
}
|
|
|
|
void
|
|
TagGroup::requiredIndex(Tag *tag,
|
|
int &req_index,
|
|
bool &exists) const
|
|
{
|
|
arrivalIndex(tag, req_index, exists);
|
|
if (exists)
|
|
req_index += arrivalCount();
|
|
}
|
|
|
|
int
|
|
TagGroup::requiredIndex(int arrival_index) const
|
|
{
|
|
return arrival_index + arrivalCount();
|
|
}
|
|
|
|
void
|
|
TagGroup::report(const StaState *sta) const
|
|
{
|
|
Report *report = sta->report();
|
|
report->print("Group %u hash = %u\n", index_, hash_);
|
|
arrivalMapReport(arrival_map_, sta);
|
|
}
|
|
|
|
void
|
|
TagGroup::reportArrivalMap(const StaState *sta) const
|
|
{
|
|
arrivalMapReport(arrival_map_, sta);
|
|
}
|
|
|
|
void
|
|
arrivalMapReport(const ArrivalMap *arrival_map,
|
|
const StaState *sta)
|
|
{
|
|
Report *report = sta->report();
|
|
ArrivalMap::ConstIterator arrival_iter(arrival_map);
|
|
while (arrival_iter.hasNext()) {
|
|
Tag *tag;
|
|
int arrival_index;
|
|
arrival_iter.next(tag, arrival_index);
|
|
report->print(" %2u %s\n",
|
|
arrival_index,
|
|
tag->asString(sta));
|
|
}
|
|
report->print("\n");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
|
|
const StaState *sta) :
|
|
default_arrival_count_(sta->corners()->count()
|
|
* TransRiseFall::index_count
|
|
* MinMax::index_count),
|
|
arrival_map_(default_arrival_count_,
|
|
TagMatchHash(match_crpr_clk_pin, sta),
|
|
TagMatchEqual(match_crpr_clk_pin, sta)),
|
|
arrivals_(default_arrival_count_),
|
|
prev_paths_(default_arrival_count_),
|
|
has_clk_tag_(false),
|
|
has_genclk_src_tag_(false),
|
|
has_filter_tag_(false),
|
|
has_loop_tag_(false),
|
|
sta_(sta)
|
|
{
|
|
}
|
|
|
|
bool
|
|
TagGroupBldr::empty()
|
|
{
|
|
return arrival_map_.empty();
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::init(Vertex *vertex)
|
|
{
|
|
vertex_ = vertex;
|
|
arrival_map_.clear();
|
|
arrivals_.clear();
|
|
prev_paths_.clear();
|
|
has_clk_tag_ = false;
|
|
has_genclk_src_tag_ = false;
|
|
has_filter_tag_ = false;
|
|
has_loop_tag_ = false;
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::reportArrivalEntries() const
|
|
{
|
|
arrivalMapReport(&arrival_map_, sta_);
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::tagArrival(Tag *tag,
|
|
// Return values.
|
|
Arrival &arrival,
|
|
int &arrival_index,
|
|
bool &exists) const
|
|
{
|
|
arrival_map_.findKey(tag, arrival_index, exists);
|
|
if (exists)
|
|
arrival = arrivals_[arrival_index];
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::tagArrival(Tag *tag,
|
|
// Return values.
|
|
Arrival &arrival,
|
|
bool &exists) const
|
|
{
|
|
int arrival_index;
|
|
arrival_map_.findKey(tag, arrival_index, exists);
|
|
if (exists)
|
|
arrival = arrivals_[arrival_index];
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::tagMatchArrival(Tag *tag,
|
|
// Return values.
|
|
Tag *&tag_match,
|
|
Arrival &arrival,
|
|
int &arrival_index) const
|
|
{
|
|
// Find matching group tag.
|
|
// Match is not necessarily equal to original tag because it
|
|
// must only satisfy tagMatch.
|
|
bool exists;
|
|
arrival_map_.findKey(tag, tag_match, arrival_index, exists);
|
|
if (exists)
|
|
arrival = arrivals_[arrival_index];
|
|
else {
|
|
tag_match = nullptr;
|
|
arrival = -1.0;
|
|
arrival_index = -1;
|
|
}
|
|
}
|
|
|
|
Arrival
|
|
TagGroupBldr::arrival(int arrival_index) const
|
|
{
|
|
return arrivals_[arrival_index];
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::setArrival(Tag *tag,
|
|
const Arrival &arrival,
|
|
PathVertexRep *prev_path)
|
|
{
|
|
Tag *tag_match;
|
|
Arrival ignore;
|
|
int arrival_index;
|
|
// Find matching group tag (not necessarily equal to original tag).
|
|
tagMatchArrival(tag, tag_match, ignore, arrival_index);
|
|
setMatchArrival(tag, tag_match, arrival, arrival_index, prev_path);
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::setMatchArrival(Tag *tag,
|
|
Tag *tag_match,
|
|
const Arrival &arrival,
|
|
int arrival_index,
|
|
PathVertexRep *prev_path)
|
|
{
|
|
if (tag_match) {
|
|
// If the group_tag exists there has to be an arrival map entry for it.
|
|
if (tag_match != tag) {
|
|
// Replace tag in arrival map.
|
|
arrival_map_.erase(tag_match);
|
|
arrival_map_.insert(tag, arrival_index);
|
|
}
|
|
arrivals_[arrival_index] = arrival;
|
|
prev_paths_[arrival_index].init(prev_path);
|
|
}
|
|
else {
|
|
arrival_index = arrivals_.size();
|
|
arrival_map_.insert(tag, arrival_index);
|
|
arrivals_.push_back(arrival);
|
|
if (prev_path)
|
|
prev_paths_.push_back(*prev_path);
|
|
else
|
|
prev_paths_.push_back(PathVertexRep());
|
|
|
|
if (tag->isClock())
|
|
has_clk_tag_ = true;
|
|
if (tag->isGenClkSrcPath())
|
|
has_genclk_src_tag_ = true;
|
|
if (tag->isFilter()
|
|
|| tag->clkInfo()->refsFilter(sta_))
|
|
has_filter_tag_ = true;
|
|
if (tag->isLoop())
|
|
has_loop_tag_ = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::deleteArrival(Tag *tag)
|
|
{
|
|
arrival_map_.erase(tag);
|
|
}
|
|
|
|
TagGroup *
|
|
TagGroupBldr::makeTagGroup(TagGroupIndex index,
|
|
const StaState *sta)
|
|
{
|
|
return new TagGroup(index, makeArrivalMap(sta),
|
|
has_clk_tag_, has_genclk_src_tag_, has_filter_tag_,
|
|
has_loop_tag_);
|
|
|
|
}
|
|
|
|
ArrivalMap *
|
|
TagGroupBldr::makeArrivalMap(const StaState *sta)
|
|
{
|
|
ArrivalMap *arrival_map = new ArrivalMap(arrival_map_.size(),
|
|
TagMatchHash(true, sta),
|
|
TagMatchEqual(true, sta));
|
|
int arrival_index = 0;
|
|
ArrivalMap::Iterator arrival_iter(arrival_map_);
|
|
while (arrival_iter.hasNext()) {
|
|
Tag *tag;
|
|
int arrival_index1;
|
|
arrival_iter.next(tag, arrival_index1);
|
|
arrival_map->insert(tag, arrival_index);
|
|
arrival_index++;
|
|
}
|
|
return arrival_map;
|
|
}
|
|
|
|
void
|
|
TagGroupBldr::copyArrivals(TagGroup *tag_group,
|
|
Arrival *arrivals,
|
|
PathVertexRep *prev_paths)
|
|
{
|
|
ArrivalMap::Iterator arrival_iter1(arrival_map_);
|
|
while (arrival_iter1.hasNext()) {
|
|
Tag *tag1;
|
|
int arrival_index1, arrival_index2;
|
|
arrival_iter1.next(tag1, arrival_index1);
|
|
bool exists2;
|
|
tag_group->arrivalIndex(tag1, arrival_index2, exists2);
|
|
if (!exists2)
|
|
internalError("tag group missing tag");
|
|
arrivals[arrival_index2] = arrivals_[arrival_index1];
|
|
if (prev_paths) {
|
|
PathVertexRep *prev_path = &prev_paths_[arrival_index1];
|
|
prev_paths[arrival_index2].init(prev_path);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
size_t
|
|
TagGroupHash::operator()(const TagGroup *group) const
|
|
{
|
|
return group->hash();
|
|
}
|
|
|
|
static bool
|
|
arrivalMapEqual(const ArrivalMap *arrival_map1,
|
|
const ArrivalMap *arrival_map2)
|
|
{
|
|
int arrival_count1 = arrival_map1->size();
|
|
int arrival_count2 = arrival_map2->size();
|
|
if (arrival_count1 == arrival_count2) {
|
|
ArrivalMap::ConstIterator arrival_iter1(arrival_map1);
|
|
while (arrival_iter1.hasNext()) {
|
|
Tag *tag1, *tag2;
|
|
int arrival_index1, arrival_index2;
|
|
arrival_iter1.next(tag1, arrival_index1);
|
|
bool exists2;
|
|
arrival_map2->findKey(tag1, tag2, arrival_index2, exists2);
|
|
if (!exists2
|
|
// ArrivalMap equal function is TagMatchEqual, so make sure
|
|
// the tag is an exact match.
|
|
|| tag2 != tag1)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
TagGroupEqual::operator()(const TagGroup *tag_group1,
|
|
const TagGroup *tag_group2) const
|
|
{
|
|
return tag_group1 == tag_group2
|
|
|| (tag_group1->hash() == tag_group2->hash()
|
|
&& arrivalMapEqual(tag_group1->arrivalMap(),
|
|
tag_group2->arrivalMap()));
|
|
}
|
|
|
|
} // namespace
|