CycleAccting use UnorderedSet
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
fd01c54d8d
commit
ad61c71ce1
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "DisallowCopyAssign.hh"
|
||||
#include "UnorderedSet.hh"
|
||||
#include "MinMax.hh"
|
||||
#include "TimingRole.hh"
|
||||
#include "StaState.hh"
|
||||
|
|
@ -24,6 +24,45 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
class CycleAcctingHash
|
||||
{
|
||||
public:
|
||||
size_t operator()(const CycleAccting *acct) const;
|
||||
};
|
||||
|
||||
class CycleAcctingEqual
|
||||
{
|
||||
public:
|
||||
bool operator()(const CycleAccting *acct1,
|
||||
const CycleAccting *acct2) const;
|
||||
};
|
||||
|
||||
class CycleAcctingLess
|
||||
{
|
||||
public:
|
||||
bool operator()(const CycleAccting *acct1,
|
||||
const CycleAccting *acct2) const;
|
||||
};
|
||||
|
||||
typedef UnorderedSet<CycleAccting*, CycleAcctingHash, CycleAcctingEqual> CycleAcctingSet;
|
||||
|
||||
class CycleAcctings
|
||||
{
|
||||
public:
|
||||
CycleAcctings(Sdc *sdc);
|
||||
~CycleAcctings();
|
||||
void clear();
|
||||
// Find the cycle accounting info for paths that start at src clock
|
||||
// edge and end at target clock edge.
|
||||
CycleAccting *cycleAccting(const ClockEdge *src,
|
||||
const ClockEdge *tgt);
|
||||
void reportClkToClkMaxCycleWarnings(Report *report);
|
||||
|
||||
private:
|
||||
Sdc *sdc_;
|
||||
CycleAcctingSet cycle_acctings_;
|
||||
};
|
||||
|
||||
class CycleAccting
|
||||
{
|
||||
public:
|
||||
|
|
@ -81,24 +120,4 @@ private:
|
|||
bool max_cycles_exceeded_;
|
||||
};
|
||||
|
||||
class CycleAcctingLess
|
||||
{
|
||||
public:
|
||||
bool operator()(const CycleAccting *acct1,
|
||||
const CycleAccting *acct2) const;
|
||||
};
|
||||
|
||||
class CycleAcctingHash
|
||||
{
|
||||
public:
|
||||
size_t operator()(const CycleAccting *acct) const;
|
||||
};
|
||||
|
||||
class CycleAcctingEqual
|
||||
{
|
||||
public:
|
||||
bool operator()(const CycleAccting *acct1,
|
||||
const CycleAccting *acct2) const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -1,453 +0,0 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2020, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include "Hash.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
template <class KEY> class HashSetBucket;
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
class HashSet
|
||||
{
|
||||
public:
|
||||
HashSet();
|
||||
explicit HashSet(size_t capacity,
|
||||
bool auto_resize);
|
||||
explicit HashSet(size_t capacity,
|
||||
bool auto_resize,
|
||||
HASH hash,
|
||||
EQUAL equal);
|
||||
~HashSet();
|
||||
// Number of objects in the table.
|
||||
size_t size() const { return size_; }
|
||||
// Number of hash buckets.
|
||||
size_t capacity() const { return capacity_; }
|
||||
// Multi-threaded findKey is safe during resize.
|
||||
void reserve(size_t capacity);
|
||||
void insert(KEY key);
|
||||
KEY findKey(KEY key);
|
||||
KEY findKey(KEY key) const;
|
||||
bool hasKey(KEY key);
|
||||
void erase(KEY key);
|
||||
bool empty() const;
|
||||
void clear();
|
||||
void deleteContentsClear();
|
||||
int longestBucketLength() const;
|
||||
size_t longestBucketHash() const;
|
||||
int bucketLength(size_t hash) const;
|
||||
|
||||
void
|
||||
deleteContents()
|
||||
{
|
||||
Iterator iter(this);
|
||||
while (iter.hasNext())
|
||||
delete iter.next();
|
||||
}
|
||||
|
||||
// Java style container itererator
|
||||
// Map::Iterator<string *, Value, stringLess> iter(map);
|
||||
// while (iter.hasNext()) {
|
||||
// Value *v = iter.next();
|
||||
// }
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator() : container_(nullptr) {}
|
||||
explicit Iterator(HashSet<KEY, HASH, EQUAL> *container)
|
||||
{ init(container); }
|
||||
explicit Iterator(HashSet<KEY, HASH, EQUAL> &container)
|
||||
{ init(container); }
|
||||
void init(HashSet<KEY, HASH, EQUAL> *container)
|
||||
{ container_ = container;
|
||||
hash_= 0;
|
||||
next_ = nullptr;
|
||||
if (container_)
|
||||
findNext();
|
||||
}
|
||||
void init(HashSet<KEY, HASH, EQUAL> &container)
|
||||
{ container_ = &container;
|
||||
hash_= 0;
|
||||
next_ = nullptr;
|
||||
if (container_)
|
||||
findNext();
|
||||
}
|
||||
bool hasNext() { return container_ && next_ != nullptr; }
|
||||
KEY next() {
|
||||
HashSetBucket<KEY> *next = next_;
|
||||
findNext();
|
||||
return next->key();
|
||||
}
|
||||
HashSet<KEY, HASH, EQUAL> *container() { return container_; }
|
||||
|
||||
private:
|
||||
void
|
||||
findNext()
|
||||
{
|
||||
if (next_)
|
||||
next_ = next_->next();
|
||||
while (next_ == nullptr
|
||||
&& hash_ < container_->capacity())
|
||||
next_ = container_->table_[hash_++];
|
||||
}
|
||||
HashSet<KEY, HASH, EQUAL> *container_;
|
||||
size_t hash_;
|
||||
HashSetBucket<KEY> *next_;
|
||||
};
|
||||
|
||||
class ConstIterator
|
||||
{
|
||||
public:
|
||||
ConstIterator() : container_(nullptr) {}
|
||||
explicit ConstIterator(const HashSet<KEY, HASH, EQUAL> *container)
|
||||
{ init(container); }
|
||||
explicit ConstIterator(const HashSet<KEY, HASH, EQUAL> &container)
|
||||
{ init(container); }
|
||||
void init(const HashSet<KEY, HASH, EQUAL> *container)
|
||||
{ container_ = container; hash_= 0; next_ = nullptr; findNext(); }
|
||||
void init(HashSet<KEY, HASH, EQUAL> &container)
|
||||
{ container_ = &container; hash_= 0; next_ = nullptr; findNext(); }
|
||||
bool hasNext() { return container_ && next_ != nullptr; }
|
||||
KEY next() {
|
||||
HashSetBucket<KEY> *next = next_;
|
||||
findNext();
|
||||
return next->key();
|
||||
}
|
||||
HashSet<KEY, HASH, EQUAL> *container() { return container_; }
|
||||
|
||||
private:
|
||||
void
|
||||
findNext()
|
||||
{
|
||||
if (next_)
|
||||
next_ = next_->next();
|
||||
while (next_ == nullptr
|
||||
&& hash_ < container_->capacity())
|
||||
next_ = container_->table_[hash_++];
|
||||
}
|
||||
const HashSet<KEY, HASH, EQUAL> *container_;
|
||||
size_t hash_;
|
||||
HashSetBucket<KEY> *next_;
|
||||
};
|
||||
|
||||
protected:
|
||||
void initTable();
|
||||
static const int default_capacity = (2 << 6) - 1;
|
||||
|
||||
// Table size.
|
||||
size_t capacity_;
|
||||
bool auto_resize_;
|
||||
HASH hash_;
|
||||
EQUAL equal_;
|
||||
size_t size_;
|
||||
HashSetBucket<KEY> **table_;
|
||||
HashSet *tmp_;
|
||||
};
|
||||
|
||||
template <class KEY>
|
||||
class HashSetBucket
|
||||
{
|
||||
public:
|
||||
HashSetBucket(KEY key, HashSetBucket *next);
|
||||
KEY key() const { return key_; }
|
||||
void setKey(KEY key) { key_ = key; }
|
||||
HashSetBucket *next() const { return next_; }
|
||||
void setNext(HashSetBucket *next) { next_ = next; }
|
||||
|
||||
private:
|
||||
KEY key_;
|
||||
HashSetBucket *next_;
|
||||
};
|
||||
|
||||
template <class KEY>
|
||||
HashSetBucket<KEY>::HashSetBucket(KEY key,
|
||||
HashSetBucket *next) :
|
||||
key_(key),
|
||||
next_(next)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
HashSet<KEY, HASH, EQUAL>::HashSet() :
|
||||
capacity_(default_capacity),
|
||||
auto_resize_(true),
|
||||
hash_(HASH()),
|
||||
equal_(EQUAL())
|
||||
{
|
||||
initTable();
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
HashSet<KEY, HASH, EQUAL>::HashSet(size_t capacity,
|
||||
bool auto_resize) :
|
||||
capacity_(capacity),
|
||||
auto_resize_(auto_resize),
|
||||
hash_(HASH()),
|
||||
equal_(EQUAL())
|
||||
{
|
||||
initTable();
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
HashSet<KEY, HASH, EQUAL>::HashSet(size_t capacity,
|
||||
bool auto_resize,
|
||||
HASH hash,
|
||||
EQUAL equal) :
|
||||
capacity_(capacity),
|
||||
auto_resize_(auto_resize),
|
||||
hash_(hash),
|
||||
equal_(equal)
|
||||
{
|
||||
initTable();
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::initTable()
|
||||
{
|
||||
size_ = 0;
|
||||
tmp_ = nullptr;
|
||||
table_ = new HashSetBucket<KEY>*[capacity_];
|
||||
for (size_t i = 0; i < capacity_; i++)
|
||||
table_[i] = nullptr;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
HashSet<KEY, HASH, EQUAL>::~HashSet()
|
||||
{
|
||||
for (size_t hash = 0; hash < capacity_; hash++) {
|
||||
HashSetBucket<KEY> *next;
|
||||
for (HashSetBucket<KEY> *bucket = table_[hash];
|
||||
bucket;
|
||||
bucket = next) {
|
||||
next = bucket->next();
|
||||
delete bucket;
|
||||
}
|
||||
}
|
||||
delete [] table_;
|
||||
delete tmp_;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
KEY
|
||||
HashSet<KEY, HASH, EQUAL>::findKey(KEY key) const
|
||||
{
|
||||
size_t hash = hash_(key) % capacity_;
|
||||
HashSetBucket<KEY> *head = table_[hash];
|
||||
for (HashSetBucket<KEY> *bucket = head; bucket; bucket = bucket->next()) {
|
||||
KEY bucket_key = bucket->key();
|
||||
if (equal_(bucket_key, key)) {
|
||||
return bucket_key;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
KEY
|
||||
HashSet<KEY, HASH, EQUAL>::findKey(KEY key)
|
||||
{
|
||||
size_t hash = hash_(key) % capacity_;
|
||||
HashSetBucket<KEY> *head = table_[hash];
|
||||
for (HashSetBucket<KEY> *bucket = head; bucket; bucket = bucket->next()) {
|
||||
KEY bucket_key = bucket->key();
|
||||
if (equal_(bucket_key, key)) {
|
||||
return bucket_key;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
bool
|
||||
HashSet<KEY, HASH, EQUAL>::hasKey(KEY key)
|
||||
{
|
||||
size_t hash = hash_(key) % capacity_;
|
||||
HashSetBucket<KEY> *head = table_[hash];
|
||||
for (HashSetBucket<KEY> *bucket = head; bucket; bucket = bucket->next()) {
|
||||
KEY bucket_key = bucket->key();
|
||||
if (equal_(bucket_key, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::insert(KEY key)
|
||||
{
|
||||
size_t hash = hash_(key) % capacity_;
|
||||
HashSetBucket<KEY> *head = table_[hash];
|
||||
for (HashSetBucket<KEY> *bucket = head; bucket; bucket = bucket->next()) {
|
||||
if (equal_(bucket->key(), key)) {
|
||||
bucket->setKey(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
HashSetBucket<KEY> *bucket = new HashSetBucket<KEY>(key, head);
|
||||
table_[hash] = bucket;
|
||||
size_++;
|
||||
if (size_ > capacity_
|
||||
&& auto_resize_)
|
||||
reserve(nextMersenne(capacity_));
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::reserve(size_t capacity)
|
||||
{
|
||||
if (capacity != capacity_) {
|
||||
if (size_ == 0) {
|
||||
// Table is empty.
|
||||
capacity_ = capacity;
|
||||
delete [] table_;
|
||||
delete tmp_;
|
||||
initTable();
|
||||
}
|
||||
else {
|
||||
delete tmp_;
|
||||
// Copy entries to tmp.
|
||||
tmp_ = new HashSet<KEY, HASH, EQUAL>(capacity, auto_resize_,
|
||||
hash_, equal_);
|
||||
for (size_t hash = 0; hash < capacity_; hash++) {
|
||||
for (HashSetBucket<KEY> *bucket = table_[hash];
|
||||
bucket;
|
||||
bucket = bucket->next())
|
||||
tmp_->insert(bucket->key());
|
||||
}
|
||||
|
||||
size_t prev_capacity = capacity_;
|
||||
HashSetBucket<KEY> **prev_table = table_;
|
||||
|
||||
// Switch over.
|
||||
table_ = tmp_->table_;
|
||||
capacity_ = capacity;
|
||||
|
||||
tmp_->capacity_ = prev_capacity;
|
||||
tmp_->table_ = prev_table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::erase(KEY key)
|
||||
{
|
||||
size_t hash = hash_(key) % capacity_;
|
||||
HashSetBucket<KEY> *head = table_[hash];
|
||||
HashSetBucket<KEY> *prev = nullptr;
|
||||
for (HashSetBucket<KEY> *bucket = head; bucket; bucket = bucket->next()) {
|
||||
if (equal_(bucket->key(), key)) {
|
||||
if (prev)
|
||||
prev->setNext(bucket->next());
|
||||
else
|
||||
table_[hash] = bucket->next();
|
||||
delete bucket;
|
||||
size_--;
|
||||
break;
|
||||
}
|
||||
prev = bucket;
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::deleteContentsClear()
|
||||
{
|
||||
if (size_ > 0) {
|
||||
for (size_t hash = 0; hash < capacity_; hash++) {
|
||||
HashSetBucket<KEY> *next;
|
||||
for (HashSetBucket<KEY> *bucket = table_[hash];
|
||||
bucket;
|
||||
bucket = next) {
|
||||
delete bucket->key();
|
||||
next = bucket->next();
|
||||
delete bucket;
|
||||
}
|
||||
table_[hash] = nullptr;
|
||||
}
|
||||
size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
void
|
||||
HashSet<KEY, HASH, EQUAL>::clear()
|
||||
{
|
||||
if (size_ > 0) {
|
||||
for (size_t hash = 0; hash < capacity_; hash++) {
|
||||
HashSetBucket<KEY> *next;
|
||||
for (HashSetBucket<KEY> *bucket = table_[hash];
|
||||
bucket;
|
||||
bucket = next) {
|
||||
next = bucket->next();
|
||||
delete bucket;
|
||||
}
|
||||
table_[hash] = nullptr;
|
||||
}
|
||||
size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
bool
|
||||
HashSet<KEY, HASH, EQUAL>::empty() const
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
int
|
||||
HashSet<KEY, HASH, EQUAL>::longestBucketLength() const
|
||||
{
|
||||
return bucketLength(longestBucketHash());
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
size_t
|
||||
HashSet<KEY, HASH, EQUAL>::longestBucketHash() const
|
||||
{
|
||||
int longest = 0;
|
||||
size_t longest_hash = 0;
|
||||
for (size_t hash = 0; hash < capacity_; hash++) {
|
||||
int length = bucketLength(hash);
|
||||
if (length > longest) {
|
||||
longest = length;
|
||||
longest_hash = hash;
|
||||
}
|
||||
}
|
||||
return longest_hash;
|
||||
}
|
||||
|
||||
template <class KEY, class HASH, class EQUAL>
|
||||
int
|
||||
HashSet<KEY, HASH, EQUAL>::bucketLength(size_t hash) const
|
||||
{
|
||||
int length = 0;
|
||||
for (HashSetBucket<KEY> *bucket = table_[hash];
|
||||
bucket;
|
||||
bucket = bucket->next())
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
#include "StringUtil.hh"
|
||||
#include "StringSet.hh"
|
||||
#include "Map.hh"
|
||||
#include "HashSet.hh"
|
||||
#include "UnorderedMap.hh"
|
||||
#include "MinMax.hh"
|
||||
#include "StaState.hh"
|
||||
|
|
@ -107,8 +106,6 @@ typedef Set<InputDelay*> InputDelaySet;
|
|||
typedef Map<const Pin*,InputDelaySet*> InputDelaysPinMap;
|
||||
typedef Set<OutputDelay*> OutputDelaySet;
|
||||
typedef Map<const Pin*,OutputDelaySet*> OutputDelaysPinMap;
|
||||
// Use HashSet so no read lock is required.
|
||||
typedef HashSet<CycleAccting*, CycleAcctingHash, CycleAcctingEqual> CycleAcctingSet;
|
||||
typedef Set<Instance*> InstanceSet;
|
||||
typedef UnorderedMap<const Pin*,ExceptionPathSet*> PinExceptionsMap;
|
||||
typedef Map<const Clock*,ExceptionPathSet*> ClockExceptionsMap;
|
||||
|
|
@ -1286,7 +1283,7 @@ protected:
|
|||
ClockGatingCheckMap clk_gating_check_map_;
|
||||
InstanceClockGatingCheckMap inst_clk_gating_check_map_;
|
||||
PinClockGatingCheckMap pin_clk_gating_check_map_;
|
||||
CycleAcctingSet cycle_acctings_;
|
||||
CycleAcctings cycle_acctings_;
|
||||
std::mutex cycle_acctings_lock_;
|
||||
DataChecksMap data_checks_from_map_;
|
||||
DataChecksMap data_checks_to_map_;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class Sdc;
|
|||
class Clock;
|
||||
class ClockEdge;
|
||||
class CycleAccting;
|
||||
class CycleAcctingLess;
|
||||
class InputDelay;
|
||||
class OutputDelay;
|
||||
class FalsePath;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,80 @@
|
|||
#include "Units.hh"
|
||||
#include "TimingRole.hh"
|
||||
#include "Clock.hh"
|
||||
#include "Sdc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
CycleAcctings::CycleAcctings(Sdc *sdc) :
|
||||
sdc_(sdc)
|
||||
{
|
||||
}
|
||||
|
||||
CycleAcctings::~CycleAcctings()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void
|
||||
CycleAcctings::clear()
|
||||
{
|
||||
cycle_acctings_.deleteContentsClear();
|
||||
}
|
||||
|
||||
// Determine cycle accounting "on demand".
|
||||
CycleAccting *
|
||||
CycleAcctings::cycleAccting(const ClockEdge *src,
|
||||
const ClockEdge *tgt)
|
||||
{
|
||||
if (src == nullptr)
|
||||
src = tgt;
|
||||
CycleAccting probe(src, tgt);
|
||||
CycleAccting *acct = cycle_acctings_.findKey(&probe);
|
||||
if (acct == nullptr) {
|
||||
acct = new CycleAccting(src, tgt);
|
||||
if (src == sdc_->defaultArrivalClockEdge())
|
||||
acct->findDefaultArrivalSrcDelays();
|
||||
else
|
||||
acct->findDelays(sdc_);
|
||||
cycle_acctings_.insert(acct);
|
||||
}
|
||||
return acct;
|
||||
}
|
||||
|
||||
void
|
||||
CycleAcctings::reportClkToClkMaxCycleWarnings(Report *report)
|
||||
{
|
||||
// Find cycle acctings that exceed max cycle count. Eliminate
|
||||
// duplicate warnings between different src/tgt clk edges.
|
||||
ClockPairSet clk_warnings;
|
||||
for (Clock *src_clk : *sdc_->clocks()) {
|
||||
for (RiseFall *src_rf : RiseFall::range()) {
|
||||
ClockEdge *src = src_clk->edge(src_rf);
|
||||
for (Clock *tgt_clk : *sdc_->clocks()) {
|
||||
for (RiseFall *tgt_rf : RiseFall::range()) {
|
||||
ClockEdge *tgt = tgt_clk->edge(tgt_rf);
|
||||
CycleAccting probe(src, tgt);
|
||||
CycleAccting *acct = cycle_acctings_.findKey(&probe);
|
||||
if (acct && acct->maxCyclesExceeded()) {
|
||||
// Canonicalize the warning wrt src/tgt.
|
||||
ClockPair clk_pair1(src_clk, tgt_clk);
|
||||
ClockPair clk_pair2(tgt_clk, src_clk);
|
||||
if (!clk_warnings.hasKey(clk_pair1)
|
||||
&& !clk_warnings.hasKey(clk_pair2)) {
|
||||
report->warn(9, "No common period was found between clocks %s and %s.",
|
||||
src_clk->name(),
|
||||
tgt_clk->name());
|
||||
clk_warnings.insert(clk_pair1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CycleAccting::CycleAccting(const ClockEdge *src,
|
||||
const ClockEdge *tgt) :
|
||||
src_(src),
|
||||
|
|
|
|||
54
sdc/Sdc.cc
54
sdc/Sdc.cc
|
|
@ -92,6 +92,7 @@ Sdc::Sdc(StaState *sta) :
|
|||
clk_group_same_(nullptr),
|
||||
clk_sense_map_(network_),
|
||||
clk_gating_check_(nullptr),
|
||||
cycle_acctings_(this),
|
||||
input_delay_index_(0),
|
||||
port_cap_map_(nullptr),
|
||||
net_wire_cap_map_(nullptr),
|
||||
|
|
@ -2413,65 +2414,20 @@ CycleAccting *
|
|||
Sdc::cycleAccting(const ClockEdge *src,
|
||||
const ClockEdge *tgt)
|
||||
{
|
||||
if (src == nullptr)
|
||||
src = tgt;
|
||||
CycleAccting *acct;
|
||||
CycleAccting probe(src, tgt);
|
||||
acct = cycle_acctings_.findKey(&probe);
|
||||
if (acct == nullptr) {
|
||||
UniqueLock lock(cycle_acctings_lock_);
|
||||
// Recheck with lock.
|
||||
acct = cycle_acctings_.findKey(&probe);
|
||||
if (acct == nullptr) {
|
||||
acct = new CycleAccting(src, tgt);
|
||||
if (src == defaultArrivalClockEdge())
|
||||
acct->findDefaultArrivalSrcDelays();
|
||||
else
|
||||
acct->findDelays(this);
|
||||
cycle_acctings_.insert(acct);
|
||||
}
|
||||
}
|
||||
return acct;
|
||||
UniqueLock lock(cycle_acctings_lock_);
|
||||
return cycle_acctings_.cycleAccting(src, tgt);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::reportClkToClkMaxCycleWarnings()
|
||||
{
|
||||
// Find cycle acctings that exceed max cycle count. Eliminate
|
||||
// duplicate warnings between different src/tgt clk edges.
|
||||
ClockPairSet clk_warnings;
|
||||
ClockPairSeq clk_warnings2;
|
||||
CycleAcctingSet::Iterator acct_iter(cycle_acctings_);
|
||||
while (acct_iter.hasNext()) {
|
||||
CycleAccting *acct = acct_iter.next();
|
||||
if (acct->maxCyclesExceeded()) {
|
||||
Clock *src = acct->src()->clock();
|
||||
Clock *tgt = acct->target()->clock();
|
||||
// Canonicalize the warning wrt src/tgt.
|
||||
if (src->index() > tgt->index())
|
||||
std::swap(src, tgt);
|
||||
ClockPair clk_pair(src, tgt);
|
||||
if (!clk_warnings.hasKey(clk_pair)) {
|
||||
clk_warnings.insert(clk_pair);
|
||||
clk_warnings2.push_back(clk_pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort clk pairs so that results are stable.
|
||||
sort(clk_warnings2, ClockPairLess());
|
||||
|
||||
for (auto pair : clk_warnings2) {
|
||||
report_->warn(9, "No common period was found between clocks %s and %s.",
|
||||
pair.first->name(),
|
||||
pair.second->name());
|
||||
}
|
||||
cycle_acctings_.reportClkToClkMaxCycleWarnings(report_);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::clearCycleAcctings()
|
||||
{
|
||||
cycle_acctings_.deleteContentsClear();
|
||||
cycle_acctings_.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -844,13 +844,12 @@ public:
|
|||
const Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
const StaState *sta);
|
||||
MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path_ends);
|
||||
~MakeEndpointPathEnds();
|
||||
virtual VertexVisitor *copy() const;
|
||||
virtual void visit(Vertex *vertex);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MakeEndpointPathEnds);
|
||||
|
||||
VisitPathEnds *visit_path_ends_;
|
||||
PathEndVisitor *path_end_visitor_;
|
||||
const Corner *corner_;
|
||||
|
|
@ -870,6 +869,15 @@ MakeEndpointPathEnds::MakeEndpointPathEnds(PathEndVisitor *path_end_visitor,
|
|||
{
|
||||
}
|
||||
|
||||
MakeEndpointPathEnds::MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path_ends) :
|
||||
visit_path_ends_(new VisitPathEnds(make_path_ends.sta_)),
|
||||
path_end_visitor_(make_path_ends.path_end_visitor_->copy()),
|
||||
corner_(make_path_ends.corner_),
|
||||
min_max_(make_path_ends.min_max_),
|
||||
sta_(make_path_ends.sta_)
|
||||
{
|
||||
}
|
||||
|
||||
MakeEndpointPathEnds::~MakeEndpointPathEnds()
|
||||
{
|
||||
delete visit_path_ends_;
|
||||
|
|
@ -903,15 +911,14 @@ PathGroups::makeGroupPathEnds(VertexSet *endpoints,
|
|||
end_visitor.visit(endpoint);
|
||||
}
|
||||
else {
|
||||
Vector<MakeEndpointPathEnds*> visitors;
|
||||
for (int i = 0; i < thread_count_; i++)
|
||||
visitors.push_back(new MakeEndpointPathEnds(visitor, corner, min_max, this));
|
||||
Vector<MakeEndpointPathEnds> visitors(thread_count_,
|
||||
MakeEndpointPathEnds(visitor, corner,
|
||||
min_max, this));
|
||||
for (auto endpoint : *endpoints) {
|
||||
dispatch_queue_->dispatch( [endpoint, &visitors](int i)
|
||||
{ visitors[i]->visit(endpoint); } );
|
||||
{ visitors[i].visit(endpoint); } );
|
||||
}
|
||||
dispatch_queue_->finishTasks();
|
||||
visitors.deleteContents();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue