OpenSTA/search/TagGroup.cc

386 lines
9.0 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2020-03-07 03:50:37 +01:00
// Copyright (c) 2020, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// 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/>.
2020-04-05 23:53:44 +02:00
#include "TagGroup.hh"
2020-04-05 20:35:51 +02:00
2020-04-05 23:53:44 +02:00
#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"
2018-09-28 17:54:21 +02:00
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_;
}
2019-08-08 23:13:02 +02:00
size_t
2018-09-28 17:54:21 +02:00
TagGroup::arrivalMapHash(ArrivalMap *arrival_map)
{
2019-08-08 23:13:02 +02:00
size_t hash = 0;
2018-09-28 17:54:21 +02:00
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->reportLine("Group %u hash = %lu", index_, hash_);
2018-09-28 17:54:21 +02:00
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);
2020-12-28 18:04:57 +01:00
report->reportLine(" %2u %s",
arrival_index,
tag->asString(sta));
2018-09-28 17:54:21 +02:00
}
2021-01-05 03:14:04 +01:00
report->reportBlankLine();
2018-09-28 17:54:21 +02:00
}
////////////////////////////////////////////////////////////////
TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
const StaState *sta) :
default_arrival_count_(sta->corners()->count()
2019-11-11 23:30:19 +01:00
* RiseFall::index_count
2018-09-28 17:54:21 +02:00
* 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 {
2019-03-13 01:25:53 +01:00
tag_match = nullptr;
2018-09-28 17:54:21 +02:00
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);
2018-09-28 17:54:21 +02:00
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);
2018-09-28 17:54:21 +02:00
}
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);
2021-01-05 03:16:03 +01:00
if (exists2) {
2021-01-05 03:14:04 +01:00
arrivals[arrival_index2] = arrivals_[arrival_index1];
2021-01-05 03:16:03 +01:00
if (prev_paths) {
PathVertexRep *prev_path = &prev_paths_[arrival_index1];
prev_paths[arrival_index2].init(prev_path);
}
}
2021-01-05 03:14:04 +01:00
else
2020-12-14 02:21:35 +01:00
sta_->report()->critical(265, "tag group missing tag");
2018-09-28 17:54:21 +02:00
}
}
////////////////////////////////////////////////////////////////
2019-08-08 23:13:02 +02:00
size_t
2018-09-28 17:54:21 +02:00
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