2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, 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
|
2022-01-04 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
//
|
|
|
|
|
// 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.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Tag.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "Clock.hh"
|
|
|
|
|
#include "PortDelay.hh"
|
|
|
|
|
#include "ExceptionPath.hh"
|
|
|
|
|
#include "Sdc.hh"
|
|
|
|
|
#include "Graph.hh"
|
|
|
|
|
#include "Corner.hh"
|
|
|
|
|
#include "Search.hh"
|
|
|
|
|
#include "PathAnalysisPt.hh"
|
|
|
|
|
#include "ClkInfo.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tagStateCmp(const Tag *tag1,
|
|
|
|
|
const Tag *tag2);
|
|
|
|
|
static bool
|
|
|
|
|
tagStateEqual(ExceptionStateSet *states1,
|
|
|
|
|
ExceptionStateSet *states2);
|
|
|
|
|
static bool
|
|
|
|
|
tagStateEqualCrpr(const Tag *tag1,
|
|
|
|
|
const Tag *tag2);
|
|
|
|
|
|
|
|
|
|
Tag::Tag(TagIndex index,
|
2023-06-02 04:28:32 +02:00
|
|
|
int rf_index,
|
2018-09-28 17:54:21 +02:00
|
|
|
PathAPIndex path_ap_index,
|
|
|
|
|
ClkInfo *clk_info,
|
|
|
|
|
bool is_clk,
|
|
|
|
|
InputDelay *input_delay,
|
|
|
|
|
bool is_segment_start,
|
|
|
|
|
ExceptionStateSet *states,
|
|
|
|
|
bool own_states,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
clk_info_(clk_info),
|
|
|
|
|
input_delay_(input_delay),
|
|
|
|
|
states_(states),
|
2023-06-02 03:16:51 +02:00
|
|
|
index_(index),
|
2018-09-28 17:54:21 +02:00
|
|
|
is_clk_(is_clk),
|
|
|
|
|
is_filter_(false),
|
|
|
|
|
is_loop_(false),
|
|
|
|
|
is_segment_start_(is_segment_start),
|
|
|
|
|
own_states_(own_states),
|
2023-06-02 04:28:32 +02:00
|
|
|
rf_index_(rf_index),
|
2018-09-28 17:54:21 +02:00
|
|
|
path_ap_index_(path_ap_index)
|
|
|
|
|
{
|
|
|
|
|
findHash();
|
|
|
|
|
if (states_) {
|
|
|
|
|
FilterPath *filter = sta->search()->filter();
|
2023-01-19 19:23:45 +01:00
|
|
|
for (ExceptionState *state : *states_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
ExceptionPath *exception = state->exception();
|
|
|
|
|
if (exception->isLoop())
|
|
|
|
|
is_loop_ = true;
|
|
|
|
|
if (exception == filter)
|
|
|
|
|
is_filter_ = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Tag::~Tag()
|
|
|
|
|
{
|
|
|
|
|
if (own_states_ && states_)
|
|
|
|
|
delete states_;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 01:59:48 +02:00
|
|
|
std::string
|
2025-03-31 00:27:53 +02:00
|
|
|
Tag::to_string(const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-31 00:27:53 +02:00
|
|
|
return to_string(true, true, sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-12 01:59:48 +02:00
|
|
|
std::string
|
2025-03-31 00:27:53 +02:00
|
|
|
Tag::to_string(bool report_index,
|
|
|
|
|
bool report_rf_min_max,
|
|
|
|
|
const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
const Network *network = sta->network();
|
|
|
|
|
const Corners *corners = sta->corners();
|
2025-04-12 01:59:48 +02:00
|
|
|
std::string result;
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
if (report_index)
|
2024-07-20 02:03:03 +02:00
|
|
|
result += std::to_string(index_);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-09-26 23:40:42 +02:00
|
|
|
if (report_rf_min_max) {
|
|
|
|
|
const RiseFall *rf = transition();
|
|
|
|
|
PathAnalysisPt *path_ap = corners->findPathAnalysisPt(path_ap_index_);
|
2024-07-20 02:03:03 +02:00
|
|
|
result += " ";
|
2025-03-31 00:27:53 +02:00
|
|
|
result += rf->to_string().c_str();
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " ";
|
2025-03-31 00:27:53 +02:00
|
|
|
result += path_ap->pathMinMax()->to_string();
|
2023-03-26 15:34:36 +02:00
|
|
|
result += "/";
|
|
|
|
|
result += std::to_string(path_ap_index_);
|
2020-09-26 23:40:42 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2024-07-20 02:03:03 +02:00
|
|
|
result += " ";
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *clk_edge = clkEdge();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_edge)
|
2023-03-26 15:34:36 +02:00
|
|
|
result += clk_edge->name();
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2023-03-26 15:34:36 +02:00
|
|
|
result += "unclocked";
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
bool is_genclk_src = clk_info_->isGenClkSrcPath();
|
|
|
|
|
if (is_clk_ || is_genclk_src) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " (";
|
2018-09-28 17:54:21 +02:00
|
|
|
if (is_clk_) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += "clock";
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_info_->isPropagated())
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " prop";
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " ideal";
|
2018-09-28 17:54:21 +02:00
|
|
|
if (is_genclk_src)
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " ";
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if (clk_info_->isGenClkSrcPath())
|
2023-03-26 15:34:36 +02:00
|
|
|
result += "genclk";
|
|
|
|
|
result += ")";
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Pin *clk_src = clkSrc();
|
|
|
|
|
if (clk_src) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " clk_src ";
|
|
|
|
|
result += network->pathName(clk_src);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *crpr_clk_path = clk_info_->crprClkPath(sta);
|
|
|
|
|
if (crpr_clk_path != nullptr) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " crpr_pin ";
|
2025-03-27 02:21:03 +01:00
|
|
|
result += network->pathName(crpr_clk_path->pin(sta));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (input_delay_) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " input ";
|
|
|
|
|
result += network->pathName(input_delay_->pin());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_segment_start_)
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " segment_start";
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
if (states_) {
|
2023-01-19 19:23:45 +01:00
|
|
|
for (ExceptionState *state : *states_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
ExceptionPath *exception = state->exception();
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " ";
|
|
|
|
|
result += exception->asString(network);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (state->nextThru()) {
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " (next thru ";
|
|
|
|
|
result += state->nextThru()->asString(network);
|
|
|
|
|
result += ")";
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-03-13 01:25:53 +01:00
|
|
|
if (exception->thrus() != nullptr)
|
2023-03-26 15:34:36 +02:00
|
|
|
result += " (thrus complete)";
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-31 00:27:53 +02:00
|
|
|
return result;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag::transition() const
|
|
|
|
|
{
|
2023-06-02 04:28:32 +02:00
|
|
|
return RiseFall::find(rf_index_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PathAnalysisPt *
|
|
|
|
|
Tag::pathAnalysisPt(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Corners *corners = sta->corners();
|
|
|
|
|
return corners->findPathAnalysisPt(path_ap_index_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tag::setStates(ExceptionStateSet *states)
|
|
|
|
|
{
|
|
|
|
|
states_ = states;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag::clkEdge() const
|
|
|
|
|
{
|
|
|
|
|
return clk_info_->clkEdge();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag::clock() const
|
|
|
|
|
{
|
|
|
|
|
return clk_info_->clock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Pin *
|
|
|
|
|
Tag::clkSrc() const
|
|
|
|
|
{
|
|
|
|
|
return clk_info_->clkSrc();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Tag::isGenClkSrcPath() const
|
|
|
|
|
{
|
|
|
|
|
return clk_info_->isGenClkSrcPath();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag::genClkSrcPathClk(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (clk_info_->isGenClkSrcPath()
|
|
|
|
|
&& states_) {
|
|
|
|
|
FilterPath *filter = sta->search()->filter();
|
2023-01-19 19:23:45 +01:00
|
|
|
for (ExceptionState *state : *states_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
ExceptionPath *except = state->exception();
|
|
|
|
|
if (except->isFilter()
|
|
|
|
|
&& except != filter) {
|
|
|
|
|
ExceptionTo *to = except->to();
|
|
|
|
|
if (to) {
|
|
|
|
|
ClockSet *clks = to->clks();
|
|
|
|
|
if (clks && clks->size() == 1) {
|
|
|
|
|
ClockSet::Iterator clk_iter(clks);
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *clk = clk_iter.next();
|
2018-09-28 17:54:21 +02:00
|
|
|
return clk;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Tag::findHash()
|
|
|
|
|
{
|
|
|
|
|
// Common to hash_ and match_hash_.
|
|
|
|
|
hash_ = hash_init_value;
|
2023-06-02 04:28:32 +02:00
|
|
|
hashIncr(hash_, rf_index_);
|
2018-09-28 17:54:21 +02:00
|
|
|
hashIncr(hash_, path_ap_index_);
|
|
|
|
|
hashIncr(hash_, is_clk_);
|
|
|
|
|
hashIncr(hash_, is_segment_start_);
|
|
|
|
|
if (states_) {
|
2023-01-19 19:23:45 +01:00
|
|
|
for (ExceptionState *state : *states_)
|
2018-09-28 17:54:21 +02:00
|
|
|
hashIncr(hash_, state->hash());
|
|
|
|
|
}
|
2025-09-16 22:53:16 +02:00
|
|
|
hashIncr(hash_, clk_info_->hash());
|
2018-09-28 17:54:21 +02:00
|
|
|
match_hash_ = hash_;
|
|
|
|
|
|
|
|
|
|
// Finish hash_.
|
|
|
|
|
if (input_delay_)
|
|
|
|
|
hashIncr(hash_, input_delay_->index());
|
|
|
|
|
|
|
|
|
|
// Finish match_hash_.
|
|
|
|
|
hashIncr(match_hash_, clk_info_->isGenClkSrcPath());
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 22:53:16 +02:00
|
|
|
size_t
|
|
|
|
|
Tag::hash(bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (match_crpr_clk_pin)
|
|
|
|
|
return hashSum(hash_, clk_info_->crprClkVertexId(sta));
|
|
|
|
|
else
|
|
|
|
|
return hash_;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 23:13:02 +02:00
|
|
|
size_t
|
2025-03-27 02:21:03 +01:00
|
|
|
Tag::matchHash(bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (match_crpr_clk_pin)
|
2025-03-27 02:21:03 +01:00
|
|
|
return hashSum(match_hash_, clk_info_->crprClkVertexId(sta));
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
|
|
|
|
return match_hash_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-05-09 20:28:03 +02:00
|
|
|
TagLess::TagLess(const StaState *sta) :
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
bool
|
|
|
|
|
TagLess::operator()(const Tag *tag1,
|
|
|
|
|
const Tag *tag2) const
|
|
|
|
|
{
|
2025-05-09 20:28:03 +02:00
|
|
|
return tagCmp(tag1, tag2, sta_) < 0;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
tagCmp(const Tag *tag1,
|
2025-05-09 20:28:03 +02:00
|
|
|
const Tag *tag2,
|
|
|
|
|
const StaState *sta)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (tag1 == tag2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2025-05-09 20:28:03 +02:00
|
|
|
ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
ClkInfo *clk_info2 = tag2->clkInfo();
|
2025-09-16 22:53:16 +02:00
|
|
|
int clk_cmp = ClkInfo::cmp(clk_info1, clk_info2, sta);
|
2025-05-09 20:28:03 +02:00
|
|
|
if (clk_cmp != 0)
|
|
|
|
|
return clk_cmp;
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
PathAPIndex path_ap_index1 = tag1->pathAPIndex();
|
|
|
|
|
PathAPIndex path_ap_index2 = tag2->pathAPIndex();
|
|
|
|
|
if (path_ap_index1 < path_ap_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (path_ap_index1 > path_ap_index2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2025-05-09 20:28:03 +02:00
|
|
|
int rf_index1 = tag1->rfIndex();
|
|
|
|
|
int rf_index2 = tag2->rfIndex();
|
|
|
|
|
if (rf_index1 < rf_index2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
2025-05-09 20:28:03 +02:00
|
|
|
if (rf_index1 > rf_index2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
bool is_clk1 = tag1->isClock();
|
|
|
|
|
bool is_clk2 = tag2->isClock();
|
|
|
|
|
if (!is_clk1 && is_clk2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (is_clk1 && !is_clk2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
InputDelay *input_delay1 = tag1->inputDelay();
|
|
|
|
|
InputDelay *input_delay2 = tag2->inputDelay();
|
2025-09-14 20:43:59 +02:00
|
|
|
int input_delay_index1 = input_delay1 ? input_delay1->index() : -1;
|
|
|
|
|
int input_delay_index2 = input_delay2 ? input_delay2->index() : -1;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (input_delay_index1 < input_delay_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (input_delay_index1 > input_delay_index2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
bool is_segment_start1 = tag1->isSegmentStart();
|
|
|
|
|
bool is_segment_start2 = tag2->isSegmentStart();
|
|
|
|
|
if (!is_segment_start1 && is_segment_start2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (is_segment_start1 && !is_segment_start2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return tagStateCmp(tag1, tag2);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-04 00:05:14 +02:00
|
|
|
bool
|
2018-09-28 17:54:21 +02:00
|
|
|
tagEqual(const Tag *tag1,
|
2025-09-16 22:53:16 +02:00
|
|
|
const Tag *tag2,
|
|
|
|
|
const StaState *sta)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return tag1 == tag2
|
2023-06-02 04:28:32 +02:00
|
|
|
|| (tag1->rfIndex() == tag2->rfIndex()
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->pathAPIndex() == tag2->pathAPIndex()
|
2025-09-16 22:53:16 +02:00
|
|
|
&& ClkInfo::equal(tag1->clkInfo(), tag2->clkInfo(), sta)
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->isClock() == tag2->isClock()
|
|
|
|
|
&& tag1->inputDelay() == tag2->inputDelay()
|
|
|
|
|
&& tag1->isSegmentStart() == tag2->isSegmentStart()
|
|
|
|
|
&& tagStateEqual(tag1, tag2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TagIndexLess::operator()(const Tag *tag1,
|
|
|
|
|
const Tag *tag2) const
|
|
|
|
|
{
|
|
|
|
|
return tag1->index() < tag2->index();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
TagMatchLess::TagMatchLess(bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
match_crpr_clk_pin_(match_crpr_clk_pin),
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TagMatchLess::operator()(const Tag *tag1,
|
|
|
|
|
const Tag *tag2) const
|
|
|
|
|
{
|
|
|
|
|
return tagMatchCmp(tag1, tag2, match_crpr_clk_pin_, sta_) < 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagMatch(const Tag *tag1,
|
|
|
|
|
const Tag *tag2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
return tagMatch(tag1, tag2, true, sta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagMatch(const Tag *tag1,
|
|
|
|
|
const Tag *tag2,
|
|
|
|
|
bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
const ClkInfo *clk_info2 = tag2->clkInfo();
|
|
|
|
|
return tag1 == tag2
|
|
|
|
|
|| (clk_info1->clkEdge() == clk_info2->clkEdge()
|
2023-06-02 04:28:32 +02:00
|
|
|
&& tag1->rfIndex() == tag2->rfIndex()
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->pathAPIndex() == tag2->pathAPIndex()
|
|
|
|
|
&& tag1->isClock() == tag2->isClock()
|
|
|
|
|
&& tag1->isSegmentStart() == tag2->isSegmentStart()
|
|
|
|
|
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
|
|
|
|
&& (!match_crpr_clk_pin
|
2025-04-10 23:16:00 +02:00
|
|
|
|| !sta->crprActive()
|
2025-03-27 02:21:03 +01:00
|
|
|
|| clk_info1->crprClkVertexId(sta) == clk_info2->crprClkVertexId(sta))
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tagStateEqual(tag1, tag2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
tagMatchCmp(const Tag *tag1,
|
|
|
|
|
const Tag *tag2,
|
|
|
|
|
bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
if (tag1 == tag2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2023-06-02 04:28:32 +02:00
|
|
|
int rf_index1 = tag1->rfIndex();
|
|
|
|
|
int rf_index2 = tag2->rfIndex();
|
|
|
|
|
if (rf_index1 < rf_index2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
2023-06-02 04:28:32 +02:00
|
|
|
if (rf_index1 > rf_index2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
PathAPIndex path_ap_index1 = tag1->pathAPIndex();
|
|
|
|
|
PathAPIndex path_ap_index2 = tag2->pathAPIndex();
|
|
|
|
|
if (path_ap_index1 < path_ap_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (path_ap_index1 > path_ap_index2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
const ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
const ClkInfo *clk_info2 = tag2->clkInfo();
|
|
|
|
|
const ClockEdge *clk_edge1 = clk_info1->clkEdge();
|
|
|
|
|
const ClockEdge *clk_edge2 = clk_info2->clkEdge();
|
|
|
|
|
int edge_index1 = clk_edge1 ? clk_edge1->index() : -1;
|
|
|
|
|
int edge_index2 = clk_edge2 ? clk_edge2->index() : -1;
|
|
|
|
|
if (edge_index1 < edge_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (edge_index1 > edge_index2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
bool is_clk1 = tag1->isClock();
|
|
|
|
|
bool is_clk2 = tag2->isClock();
|
|
|
|
|
if (!is_clk1 && is_clk2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (is_clk1 && !is_clk2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
bool is_genclk_src1 = clk_info1->isGenClkSrcPath();
|
|
|
|
|
bool is_genclk_src2 = clk_info2->isGenClkSrcPath();
|
|
|
|
|
if (!is_genclk_src1 && is_genclk_src2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (is_genclk_src1 && !is_genclk_src2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
bool is_segment_start1 = tag1->isSegmentStart();
|
|
|
|
|
bool is_segment_start2 = tag2->isSegmentStart();
|
|
|
|
|
if (!is_segment_start1 && is_segment_start2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (is_segment_start1 && !is_segment_start2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (match_crpr_clk_pin
|
2025-04-10 23:16:00 +02:00
|
|
|
&& sta->crprActive()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
VertexId crpr_vertex1 = clk_info1->crprClkVertexId(sta);
|
|
|
|
|
VertexId crpr_vertex2 = clk_info2->crprClkVertexId(sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (crpr_vertex1 < crpr_vertex2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (crpr_vertex1 > crpr_vertex2)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tagStateCmp(tag1, tag2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagMatchNoCrpr(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
const ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
const ClkInfo *clk_info2 = tag2->clkInfo();
|
|
|
|
|
return tag1 == tag2
|
|
|
|
|
|| (clk_info1->clkEdge() == clk_info2->clkEdge()
|
2023-06-02 04:28:32 +02:00
|
|
|
&& tag1->rfIndex() == tag2->rfIndex()
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->pathAPIndex() == tag2->pathAPIndex()
|
|
|
|
|
&& tag1->isClock() == tag2->isClock()
|
|
|
|
|
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
|
|
|
|
&& tagStateEqual(tag1, tag2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagMatchNoPathAp(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
const ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
const ClkInfo *clk_info2 = tag2->clkInfo();
|
|
|
|
|
return tag1 == tag2
|
|
|
|
|
|| (clk_info1->clkEdge() == clk_info2->clkEdge()
|
2023-06-02 04:28:32 +02:00
|
|
|
&& tag1->rfIndex() == tag2->rfIndex()
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->isClock() == tag2->isClock()
|
|
|
|
|
&& tag1->isSegmentStart() == tag2->isSegmentStart()
|
|
|
|
|
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
|
|
|
|
&& tagStateEqual(tag1, tag2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagMatchCrpr(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
const ClkInfo *clk_info1 = tag1->clkInfo();
|
|
|
|
|
const ClkInfo *clk_info2 = tag2->clkInfo();
|
|
|
|
|
return tag1 == tag2
|
|
|
|
|
|| (clk_info1->clkEdge() == clk_info2->clkEdge()
|
2023-06-02 04:28:32 +02:00
|
|
|
&& tag1->rfIndex() == tag2->rfIndex()
|
2018-09-28 17:54:21 +02:00
|
|
|
&& tag1->isClock() == tag2->isClock()
|
|
|
|
|
&& tag1->isSegmentStart() == tag2->isSegmentStart()
|
|
|
|
|
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
|
|
|
|
&& tagStateEqualCrpr(tag1, tag2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tagStateCmp(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
ExceptionStateSet *states1 = tag1->states();
|
|
|
|
|
ExceptionStateSet *states2 = tag2->states();
|
2019-03-13 01:25:53 +01:00
|
|
|
bool states_null1 = (states1 == nullptr || states1->empty());
|
|
|
|
|
bool states_null2 = (states2 == nullptr || states2->empty());
|
2018-09-28 17:54:21 +02:00
|
|
|
if (states_null1
|
|
|
|
|
&& states_null2)
|
|
|
|
|
return 0;
|
|
|
|
|
if (states_null1
|
|
|
|
|
&& !states_null2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (!states_null1
|
|
|
|
|
&& states_null2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
size_t state_size1 = states1->size();
|
|
|
|
|
size_t state_size2 = states2->size();
|
|
|
|
|
if (state_size1 < state_size2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (state_size1 > state_size2)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
ExceptionStateSet::Iterator state_iter1(states1);
|
|
|
|
|
ExceptionStateSet::Iterator state_iter2(states2);
|
|
|
|
|
while (state_iter1.hasNext()
|
|
|
|
|
&& state_iter2.hasNext()) {
|
|
|
|
|
ExceptionState *state1 = state_iter1.next();
|
|
|
|
|
ExceptionState *state2 = state_iter2.next();
|
2025-09-12 18:10:03 +02:00
|
|
|
if (exceptionStateLess(state1, state2))
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
2025-09-12 18:10:03 +02:00
|
|
|
if (exceptionStateLess(state2, state1))
|
2018-09-28 17:54:21 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
tagStateEqual(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
return tagStateEqual(tag1->states(), tag2->states());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
tagStateEqual(ExceptionStateSet *states1,
|
|
|
|
|
ExceptionStateSet *states2)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
bool states_null1 = (states1 == nullptr || states1->empty());
|
|
|
|
|
bool states_null2 = (states2 == nullptr || states2->empty());
|
2018-09-28 17:54:21 +02:00
|
|
|
if (states_null1 && states_null2)
|
|
|
|
|
return true;
|
|
|
|
|
else if (states_null1 != states_null2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
size_t state_size1 = states1->size();
|
|
|
|
|
size_t state_size2 = states2->size();
|
|
|
|
|
if (state_size1 == state_size2) {
|
|
|
|
|
ExceptionStateSet::Iterator state_iter1(states1);
|
|
|
|
|
ExceptionStateSet::Iterator state_iter2(states2);
|
|
|
|
|
while (state_iter1.hasNext()
|
|
|
|
|
&& state_iter2.hasNext()) {
|
|
|
|
|
ExceptionState *state1 = state_iter1.next();
|
|
|
|
|
ExceptionState *state2 = state_iter2.next();
|
|
|
|
|
if (state1 != state2)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-13 20:28:40 +01:00
|
|
|
// Match loop exception states only for crpr min/max paths.
|
2018-09-28 17:54:21 +02:00
|
|
|
static bool
|
|
|
|
|
tagStateEqualCrpr(const Tag *tag1,
|
|
|
|
|
const Tag *tag2)
|
|
|
|
|
{
|
|
|
|
|
ExceptionStateSet *states1 = tag1->states();
|
|
|
|
|
ExceptionStateSet *states2 = tag2->states();
|
|
|
|
|
ExceptionStateSet::Iterator state_iter1(states1);
|
|
|
|
|
ExceptionStateSet::Iterator state_iter2(states2);
|
|
|
|
|
ExceptionState *state1, *state2;
|
|
|
|
|
do {
|
2019-03-13 01:25:53 +01:00
|
|
|
state1 = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
while (state_iter1.hasNext()) {
|
|
|
|
|
state1 = state_iter1.next();
|
|
|
|
|
ExceptionPath *exception1 = state1->exception();
|
2024-11-13 20:28:40 +01:00
|
|
|
if (exception1->isLoop())
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
state1 = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
state2 = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
while (state_iter2.hasNext()) {
|
|
|
|
|
state2 = state_iter2.next();
|
|
|
|
|
ExceptionPath *exception2 = state2->exception();
|
2024-11-13 20:28:40 +01:00
|
|
|
if (exception2->isLoop())
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
state2 = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if (state1 != state2)
|
|
|
|
|
return false;
|
|
|
|
|
} while (state1 && state2);
|
2019-03-13 01:25:53 +01:00
|
|
|
return state1 == nullptr
|
|
|
|
|
&& state2 == nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-09-16 22:53:16 +02:00
|
|
|
TagHash::TagHash(const StaState *sta) :
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 23:13:02 +02:00
|
|
|
size_t
|
2021-12-10 02:19:26 +01:00
|
|
|
TagHash::operator()(const Tag *tag) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-09-16 22:53:16 +02:00
|
|
|
bool crpr_on = sta_->crprActive();
|
|
|
|
|
return tag->matchHash(crpr_on, sta_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TagEqual::TagEqual(const StaState *sta) :
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TagEqual::operator()(const Tag *tag1,
|
2021-12-10 02:19:26 +01:00
|
|
|
const Tag *tag2) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-09-16 22:53:16 +02:00
|
|
|
return tagEqual(tag1, tag2, sta_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TagMatchHash::TagMatchHash(bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
match_crpr_clk_pin_(match_crpr_clk_pin),
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 23:13:02 +02:00
|
|
|
size_t
|
2018-09-28 17:54:21 +02:00
|
|
|
TagMatchHash::operator()(const Tag *tag) const
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
return tag->matchHash(match_crpr_clk_pin_, sta_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TagMatchEqual::TagMatchEqual(bool match_crpr_clk_pin,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
match_crpr_clk_pin_(match_crpr_clk_pin),
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TagMatchEqual::operator()(const Tag *tag1,
|
|
|
|
|
const Tag *tag2) const
|
|
|
|
|
{
|
|
|
|
|
return tagMatch(tag1, tag2, match_crpr_clk_pin_, sta_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|