OpenSTA/search/TagGroup.cc

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