Compare commits

...

34 Commits

Author SHA1 Message Date
Waylander 89444a6111
Merge 335b305149 into 3b2961ebd2 2025-09-14 09:20:16 -07:00
Matt Liberty 3b2961ebd2 Merge remote-tracking branch 'parallax/master' 2025-09-12 15:55:28 +00:00
Vitor Bandeira 9870b14640
Use STA_HOME instead of CMAKE_SOURCE_DIR (#296)
When using OpenSTA as a submodule/external dependency CMAKE_SOURCE_DIR
resolves to the root of the top project instead of OpenSTA's. Using
STA_HOME resolves the path correctly and is used in other places in the
project already.

Signed-off-by: Vitor Bandeira <vvbandeira@precisioninno.com>
2025-09-12 08:52:55 -07:00
James Cherry 30c8230f68 tag group ref count w/threads
commit d7e45e73e7b3a5b9b3b00eeaaff6c5608fd15a44
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Sep 12 08:41:14 2025 -0700

    tag group ref count w/threads

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-12 08:50:58 -07:00
Matt Liberty 2412feec33
pad cells are not buffers or inverters (#294)
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
2025-09-08 17:04:21 -07:00
James Cherry aa27e3372e Genclks:: deleteGenclkSrcPaths
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-08 16:08:26 -07:00
Matt Liberty 39fd453a69 Merge remote-tracking branch 'parallax/master' 2025-09-08 20:24:47 +00:00
James Cherry dcbaaf4c05 ExpandedExceptionVisitor
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-07 15:22:06 -07:00
James Cherry 26be60906c ExpandedExceptionVisitor memory error
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-06 16:18:21 -07:00
James Cherry 2163a5c6b9 parallel dcalc with diff arc counts resolves #288
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-06 14:43:01 -07:00
James Cherry 433f9aa7d7 report_tag_arrivals
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-05 15:52:38 -07:00
James Cherry 5d02db77d7 rm Search::checkDefaultArrivalPaths
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-05 15:52:19 -07:00
James Cherry 594537b719 latch do not propagate unclked paths (eagle 20250905)
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-05 15:51:59 -07:00
Matt Liberty 2a1e49e8f4 Merge remote-tracking branch 'parallax/master' 2025-09-05 05:24:33 +00:00
James Cherry 774c3c68f1 setVertexArrivals use tag_group_lock
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-04 18:36:18 -07:00
Mateusz Gancarz 45a8a1bcc0
search: fix truncating path ends list if sorting by slack (#291) 2025-09-03 16:45:33 -07:00
James Cherry 1731dd0c38 group_path -default doc resolves #292
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-03 16:08:06 -07:00
Matt Liberty e475ee2c98 Merge remote-tracking branch 'upstream/master'
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
2025-09-03 23:00:11 +00:00
Waylander 849832a951
Fix an undefined behaviour and a memory leak (#289)
* Use a unique_ptr to avoid leaks

* Use memmove instead of memcopy

As both arguments can overlap, use memmove instead of memcopy

* Fix code style issues
2025-09-03 15:12:26 -07:00
James Cherry e4a1ebf00e TaGGroup refcount to reclaim memory
commit cd7169f99ab8b67323c444d4c22d065487e439c1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Aug 31 16:02:03 2025 -0700

    reportArrivals report_tag_index

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 658f842a776bb43eef7dbfd9a08e191c31fb9f11
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Aug 25 16:20:50 2025 -0700

    tag group ref count

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-09-03 15:05:14 -07:00
Matt Liberty 5e1cecc38b pad cells are not buffers or inverters
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
2025-09-02 17:42:06 +00:00
Matt Liberty aaec7557dc Fix leaked iterator in Sta::netSlack
(Upstreamed but commiting here on expectation of merge)

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
2025-09-01 01:46:29 +00:00
Drew Lewis 255988633f
Change DmpAlg to use preallocated arrays (#283)
* Change DmpAlg to use preallocated arrays

DmpAlg isn't called with nr_order_ > 3 so this change saves 9 news and 9
frees for each construction and destruction of the class.

* Remove nr_order size check in DmpAlg constructor

Signed-off-by: Drew Lewis <cannada@google.com>

---------

Signed-off-by: Drew Lewis <cannada@google.com>
2025-08-23 11:34:32 -07:00
James Cherry b654fd48a8 read_liberty leak resolves ORFS#1184
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-20 16:00:33 -07:00
James Cherry 70f4bc0459 latch nworst thru D->Q (eagle 20250815)
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-18 13:27:30 -07:00
Matt Liberty 872f611fea
Support redirection for report_clock_min_period (#286)
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
2025-08-15 11:28:05 -07:00
James Cherry 5b56558e7a GraphDelayCalc::findDelays no need to visit if iter empty
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-13 11:43:40 -07:00
Akash Levy 4920f673a8
JSON reporting: split out source clock path (#285) 2025-08-13 09:53:44 -07:00
James Cherry 0cd16e504a set_max_delay -from pos_latch -to neg_latch (eagle 20250808)
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-12 18:08:01 -07:00
James Cherry d31e3b06e2 doc spell check
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-12 12:32:36 -07:00
Ethan Mahintorabi 6d18003c04
util: Fix memory leak in PatternMatch (#282)
When allocating a new string object in tcl you need increment and
then decremenet the ref counter in order for objects to be correctly
collected.

Signed-off-by: Ethan Mahintorabi <ethanmoon@google.com>
2025-08-11 16:25:47 -07:00
James Cherry 82fd625199 Levelize rm relevelized limit
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-06 10:10:11 -07:00
James Cherry 12f03395ec rm bfs printf
Signed-off-by: James Cherry <cherry@parallaxsw.com>
2025-08-04 08:21:37 -07:00
Florian Chivé 335b305149
Change memcpy to memmove
Signed-off-by: Florian Chivé <62927863+Faholan@users.noreply.github.com>
2025-05-29 13:59:40 -07:00
42 changed files with 2433 additions and 2180 deletions

View File

@ -39,6 +39,7 @@ project(STA VERSION 2.7.0
option(CUDD_DIR "CUDD BDD package directory")
option(USE_TCL_READLINE "Use TCL readline package" ON)
option(ENABLE_TSAN "Compile with thread santizer enabled" OFF)
option(ENABLE_ASAN "Compile with address santizer enabled" OFF)
# Turn on to debug compiler args.
set(CMAKE_VERBOSE_MAKEFILE OFF)
@ -541,6 +542,12 @@ if(ENABLE_TSAN)
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=thread")
endif()
if(ENABLE_ASAN)
message(STATUS "Address sanitizer: ${ENABLE_ASAN}")
set(CXX_FLAGS "${CXX_FLAGS};-fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address")
endif()
target_compile_options(OpenSTA
PRIVATE
$<$<CXX_COMPILER_ID:GNU>:${CXX_FLAGS}>
@ -606,6 +613,6 @@ add_custom_target(sta_tags
add_custom_command(
TARGET OpenSTA
POST_BUILD
COMMAND ${CMAKE_SOURCE_DIR}/etc/FindMessages.tcl > ${CMAKE_SOURCE_DIR}/doc/messages.txt || true
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${STA_HOME}/etc/FindMessages.tcl > ${STA_HOME}/doc/messages.txt || true
WORKING_DIRECTORY ${STA_HOME}
)

View File

@ -263,12 +263,16 @@ protected:
// Driver parameter Newton-Raphson state.
int nr_order_;
double *x_;
double *fvec_;
double **fjac_;
double *scale_;
double *p_;
int *index_;
static constexpr int max_nr_order_ = 3;
double x_[max_nr_order_];
double fvec_[max_nr_order_];
double fjac_storage_[max_nr_order_ * max_nr_order_];
double *fjac_[max_nr_order_];
double scale_[max_nr_order_];
double p_[max_nr_order_ ];
int index_[max_nr_order_];
// Driver slew used to check load delay.
double drvr_slew_;
@ -288,27 +292,12 @@ DmpAlg::DmpAlg(int nr_order,
c1_(0.0),
nr_order_(nr_order)
{
x_ = new double[nr_order_];
fvec_ = new double[nr_order_];
scale_ = new double[nr_order_];
p_ = new double[nr_order_];
fjac_ = new double*[nr_order_];
for (int i = 0; i < nr_order_; i++)
fjac_[i] = new double[nr_order_];
index_ = new int[nr_order_];
// Only use the upper left block of the matrix
fjac_[i] = fjac_storage_ + i * max_nr_order_;
}
DmpAlg::~DmpAlg()
{
delete [] x_;
delete [] fvec_;
delete [] scale_;
delete [] p_;
for (int i = 0; i < nr_order_; i++)
delete [] fjac_[i];
delete [] fjac_;
delete [] index_;
}
DmpAlg::~DmpAlg() = default;
void
DmpAlg::init(const LibertyLibrary *drvr_library,

View File

@ -260,8 +260,10 @@ GraphDelayCalc::findDelays(Level level)
if (incremental_)
seedInvalidDelays();
FindVertexDelays visitor(this);
dcalc_count += iter_->visitParallel(level, &visitor);
if (!iter_->empty()) {
FindVertexDelays visitor(this);
dcalc_count += iter_->visitParallel(level, &visitor);
}
// Timing checks require slews at both ends of the arc,
// so find their delays after all slews are known.
@ -1010,7 +1012,7 @@ GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex,
arc1 = arc;
}
else
findParallelEdge(drvr_vertex1, edge, arc, edge1, arc1);
findParallelEdge(drvr_vertex1, arc, edge1, arc1);
// Shockingly one fpga vendor connects outputs with no timing arcs together.
if (edge1) {
Vertex *from_vertex = edge1->from(graph_);
@ -1034,7 +1036,6 @@ GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex,
// primary driver drvr_edge/drvr_arc.
void
GraphDelayCalc::findParallelEdge(Vertex *vertex,
Edge *drvr_edge,
const TimingArc *drvr_arc,
// Return values.
Edge *&edge,
@ -1045,11 +1046,10 @@ GraphDelayCalc::findParallelEdge(Vertex *vertex,
if (vertex_cell == drvr_cell) {
// Homogeneous drivers.
arc = drvr_arc;
LibertyPort *from_port = network_->libertyPort(drvr_edge->from(graph_)->pin());
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
edge = edge_iter.next();
if (network_->libertyPort(edge->from(graph_)->pin()) == from_port)
if (edge->timingArcSet() == arc->set())
return;
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -35,6 +35,7 @@
#include "PortDirection.hh"
#include "Network.hh"
#include "DcalcAnalysisPt.hh"
#include "FuncExpr.hh"
namespace sta {
@ -1293,6 +1294,11 @@ Edge::to_string(const StaState *sta) const
string str = from(graph)->to_string(sta);
str += " -> ";
str += to(graph)->to_string(sta);
FuncExpr *when = arc_set_->cond();
if (when) {
str += " ";
str += when->to_string();
}
return str;
}

View File

@ -632,7 +632,7 @@ private:
void expandFrom();
void expandThrus(ExceptionFrom *expanded_from);
void expandThru(ExceptionFrom *expanded_from,
ExceptionThruSeq::Iterator &thru_iter,
size_t next_thru_idx,
ExceptionThruSeq *expanded_thrus);
void expandTo(ExceptionFrom *expanded_from,
ExceptionThruSeq *expanded_thrus);

View File

@ -332,6 +332,7 @@ protected:
// These fields are written by multiple threads, so they
// cannot share the same word as the following bit fields.
uint32_t tag_group_index_;
uint32_t object_idx_;
// Each bit corresponds to a different BFS queue.
std::atomic<uint8_t> bfs_in_queue_; // 8
@ -343,7 +344,6 @@ protected:
// This flag distinguishes the driver and load vertices.
bool is_bidirect_drvr_:1;
unsigned object_idx_:VertexTable::idx_bits; // 7
bool is_reg_clk_:1;
bool is_disabled_constraint_:1;
bool is_gated_clk_enable_:1;

View File

@ -204,7 +204,6 @@ protected:
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findParallelEdge(Vertex *vertex,
Edge *drvr_edge,
const TimingArc *drvr_arc,
// Return values.
Edge *&edge,

View File

@ -375,6 +375,8 @@ public:
virtual const TimingRole *checkRole(const StaState *sta) const;
virtual Required requiredTime(const StaState *sta) const;
virtual Arrival borrow(const StaState *sta) const;
virtual float targetClkTime(const StaState *sta) const;
virtual float targetClkOffset(const StaState *sta) const;
Arrival targetClkWidth(const StaState *sta) const;
virtual int exceptPathCmp(const PathEnd *path_end,
const StaState *sta) const;

View File

@ -356,7 +356,8 @@ public:
TagGroup *tagGroup(const Vertex *vertex) const;
TagGroup *tagGroup(TagGroupIndex index) const;
void reportArrivals(Vertex *vertex) const;
void reportArrivals(Vertex *vertex,
bool report_tag_index) const;
Slack wnsSlack(Vertex *vertex,
PathAPIndex path_ap_index);
void levelsChangedBefore();
@ -365,9 +366,6 @@ public:
Vertex *vertex,
TagGroupBldr *tag_bldr);
void ensureDownstreamClkPins();
// Check paths from inputs from the default arrival clock
// (missing set_input_delay).
virtual bool checkDefaultArrivalPaths() { return true; }
bool matchesFilter(Path *path,
const ClockEdge *to_clk_edge);
CheckCrpr *checkCrpr() { return check_crpr_; }
@ -410,6 +408,7 @@ public:
TagGroupIndex tag_index);
void checkPrevPaths() const;
void deletePaths(Vertex *vertex);
void deleteTagGroup(TagGroup *group);
protected:
void init(StaState *sta);
@ -422,6 +421,7 @@ protected:
DcalcAnalysisPt *dcalc_ap_max);
void deleteTags();
void deleteTagsPrev();
void deleteUnusedTagGroups();
void seedInvalidArrivals();
void seedArrivals();
void findClockVertices(VertexSet &vertices);

View File

@ -1175,7 +1175,8 @@ LibertyCell::isBuffer() const
bufferPorts(input, output);
return input && output
&& hasBufferFunc(input, output)
&& !is_level_shifter_;
&& !is_level_shifter_
&& !is_pad_;
}
bool
@ -1195,7 +1196,9 @@ LibertyCell::isInverter() const
LibertyPort *output;
bufferPorts(input, output);
return input && output
&& hasInverterFunc(input, output);
&& hasInverterFunc(input, output)
&& !is_level_shifter_
&& !is_pad_;
}
bool

View File

@ -559,6 +559,8 @@ LibertyReader::defineVisitors()
defineGroupVisitor("ecsm_waveform", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform);
defineGroupVisitor("ecsm_waveform_set", &LibertyReader::beginEcsmWaveform,
&LibertyReader::endEcsmWaveform);
}
void

View File

@ -2146,9 +2146,8 @@ ExpandedExceptionVisitor::expandThrus(ExceptionFrom *expanded_from)
ExceptionThruSeq *thrus = exception_->thrus();
if (thrus) {
// Use tail recursion to expand the exception points in the thrus.
ExceptionThruSeq::Iterator thru_iter(thrus);
ExceptionThruSeq expanded_thrus;
expandThru(expanded_from, thru_iter, &expanded_thrus);
expandThru(expanded_from, 0, &expanded_thrus);
}
else
expandTo(expanded_from, nullptr);
@ -2156,40 +2155,41 @@ ExpandedExceptionVisitor::expandThrus(ExceptionFrom *expanded_from)
void
ExpandedExceptionVisitor::expandThru(ExceptionFrom *expanded_from,
ExceptionThruSeq::Iterator &thru_iter,
size_t next_thru_idx,
ExceptionThruSeq *expanded_thrus)
{
if (thru_iter.hasNext()) {
ExceptionThru *thru = thru_iter.next();
ExceptionThruSeq *thrus = exception_->thrus();
if (next_thru_idx < thrus->size()) {
ExceptionThru *thru = (*thrus)[next_thru_idx];
const RiseFallBoth *rf = thru->transition();
if (thru->pins()) {
for (const Pin *pin : *thru->pins()) {
PinSet pins(network_);
pins.insert(pin);
ExceptionThru expanded_thru(&pins, nullptr, nullptr, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, thru_iter, expanded_thrus);
expanded_thrus->pop_back();
PinSet pins(network_);
pins.insert(pin);
ExceptionThru expanded_thru(&pins, nullptr, nullptr, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, next_thru_idx + 1, expanded_thrus);
expanded_thrus->pop_back();
}
}
if (thru->nets()) {
for (const Net *net : *thru->nets()) {
NetSet nets(network_);
nets.insert(net);
ExceptionThru expanded_thru(nullptr, &nets, nullptr, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, thru_iter, expanded_thrus);
expanded_thrus->pop_back();
NetSet nets(network_);
nets.insert(net);
ExceptionThru expanded_thru(nullptr, &nets, nullptr, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, next_thru_idx + 1, expanded_thrus);
expanded_thrus->pop_back();
}
}
if (thru->instances()) {
for (const Instance *inst : *thru->instances()) {
InstanceSet insts(network_);
insts.insert(inst);
ExceptionThru expanded_thru(nullptr, nullptr, &insts, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, thru_iter, expanded_thrus);
expanded_thrus->pop_back();
InstanceSet insts(network_);
insts.insert(inst);
ExceptionThru expanded_thru(nullptr, nullptr, &insts, rf, false, network_);
expanded_thrus->push_back(&expanded_thru);
expandThru(expanded_from, next_thru_idx + 1, expanded_thrus);
expanded_thrus->pop_back();
}
}
}

View File

@ -5115,8 +5115,10 @@ ExpandException::visit(ExceptionFrom *from,
ExceptionThruSeq *thrus_clone = nullptr;
if (thrus) {
thrus_clone = new ExceptionThruSeq;
for (ExceptionThru *thru : *thrus)
thrus_clone->push_back(thru->clone(network_));
for (ExceptionThru *thru : *thrus) {
ExceptionThru *thru_clone = thru->clone(network_);
thrus_clone->push_back(thru_clone);
}
}
ExceptionTo *to_clone = nullptr;
if (to)

View File

@ -303,12 +303,14 @@ BfsIterator::checkInQueue(Vertex *vertex)
if (vertex->bfsInQueue(bfs_index_))
return;
else
printf("extra %s\n", vertex->to_string(this).c_str());
debugPrint(debug_, "bfs", 1, "extra %s",
vertex->to_string(this).c_str());
}
}
}
if (vertex->bfsInQueue(bfs_index_))
printf("missing %s\n", vertex->to_string(this).c_str());
debugPrint(debug_, "brs", 1, "missing %s",
vertex->to_string(this).c_str());
}
void

View File

@ -352,11 +352,8 @@ Genclks::seedSrcPins(Clock *clk,
{
VertexSet src_vertices(graph_);
clk->srcPinVertices(src_vertices, network_, graph_);
VertexSet::Iterator vertex_iter(src_vertices);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
for (Vertex *vertex : src_vertices)
iter.enqueue(vertex);
}
}
////////////////////////////////////////////////////////////////
@ -972,11 +969,22 @@ Genclks::recordSrcPaths(Clock *gclk)
network_->pathName(gclk_pin),
gclk->masterClk()->name());
}
// This can be narrowed to visited vertices.
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
deleteGenclkSrcPaths(gclk);
}
void
Genclks:: deleteGenclkSrcPaths(Clock *gclk)
{
GenclkInfo *genclk_info = genclkInfo(gclk);
GenClkInsertionSearchPred srch_pred(gclk, nullptr, genclk_info, this);
BfsFwdIterator insert_iter(BfsIndex::other, &srch_pred, this);
FilterPath *src_filter = genclk_info->srcFilter();
seedSrcPins(gclk, src_filter, insert_iter);
GenClkArrivalSearchPred eval_pred(gclk, this);
while (insert_iter.hasNext()) {
Vertex *vertex = insert_iter.next();
search_->deletePaths(vertex);
insert_iter.enqueueAdjacentVertices(vertex, &srch_pred);
}
}

View File

@ -130,6 +130,7 @@ private:
VertexSet &path_vertices,
VertexSet &visited_vertices,
EdgeSet *&fdbk_edges);
void deleteGenclkSrcPaths(Clock *gclk);
bool found_insertion_delays_;
GenclkSrcPathMap genclk_src_paths_;

View File

@ -93,7 +93,7 @@ Latches::latchRequired(const Path *data_path,
CycleAccting *acct = sdc_->cycleAccting(data_clk_edge,
enable_clk_edge);
// checkTgtClkTime
float tgt_clk_time = acct->requiredTime(check_role);
float tgt_clk_time = path_delay ? 0.0 : acct->requiredTime(check_role);
// checkTgtClkArrival broken down into components.
Arrival enable_arrival = max_delay
+ tgt_clk_time

View File

@ -52,7 +52,6 @@ Levelize::Levelize(StaState *sta) :
levels_valid_(false),
max_level_(0),
level_space_(10),
max_incremental_level_(std::numeric_limits<size_t>::max()),
roots_(graph_),
relevelize_from_(graph_),
observer_(nullptr)
@ -106,8 +105,7 @@ void
Levelize::ensureLevelized()
{
if (!levels_valid_) {
if (levelized_
&& relevelize_from_.size() < max_incremental_level_)
if (levelized_)
relevelize();
else
levelize();

View File

@ -108,7 +108,6 @@ protected:
bool levels_valid_;
Level max_level_;
Level level_space_;
size_t max_incremental_level_;
VertexSet roots_;
VertexSet relevelize_from_;
GraphLoopSeq loops_;

View File

@ -1193,6 +1193,24 @@ PathEndLatchCheck::checkRole(const StaState *sta) const
return TimingRole::latchSetup();
}
float
PathEndLatchCheck::targetClkTime(const StaState *sta) const
{
if (path_delay_)
return 0.0;
else
return PathEndClkConstrained::targetClkTime(sta);
}
float
PathEndLatchCheck::targetClkOffset(const StaState *sta) const
{
if (path_delay_)
return -targetClkEdge(sta)->time();
else
return PathEndClkConstrained::targetClkOffset(sta);
}
Required
PathEndLatchCheck::requiredTime(const StaState *sta) const
{

View File

@ -35,6 +35,7 @@
#include "PathAnalysisPt.hh"
#include "Tag.hh"
#include "Search.hh"
#include "Latches.hh"
#include "PathEnd.hh"
#include "Path.hh"
@ -219,7 +220,8 @@ PathEnum::reportDiversionPath(Diversion *div)
p->to_string(this).c_str(),
delayAsString(p->arrival(), this),
Path::equal(p, after_div, this) ? " <-after diversion" : "");
if (p != path && network_->isLatchData(p->pin(this)))
if (p != path
&& network_->isLatchData(p->pin(this)))
break;
p = p->prevPath();
}
@ -529,13 +531,23 @@ PathEnum::divSlack(Path *before_div,
const TimingArc *div_arc,
const PathAnalysisPt *path_ap)
{
Arrival arc_arrival = before_div->arrival();
Arrival before_div_arrival = before_div->arrival();
if (div_edge) {
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
div_arc, div_edge,
false, path_ap);
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
return div_arrival - arc_arrival;
if (div_edge->role()->isLatchDtoQ()) {
Arrival div_arrival;
ArcDelay div_delay;
Tag *q_tag;
latches_->latchOutArrival(after_div, div_arc, div_edge, path_ap,
q_tag, div_delay, div_arrival);
return div_arrival - before_div_arrival;
}
else {
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
div_arc, div_edge,
false, path_ap);
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
return div_arrival - before_div_arrival;
}
}
else {
report()->error(1370, "path diversion missing edge.");
@ -634,39 +646,56 @@ PathEnum::updatePathHeadDelays(PathSeq &paths,
Tag *prev_tag = after_div->tag(this);
ClkInfo *prev_clk_info = prev_tag->clkInfo();
Arrival prev_arrival = search_->clkPathArrival(after_div);
for (int i = paths.size() - 1; i >= 0; i--) {
int path_idx_max = paths.size() - 1;
// paths[0] is the path endpoint
for (int i = path_idx_max; i >= 0; i--) {
Path *path = paths[i];
TimingArc *arc = path->prevArc(this);
Edge *edge = path->prevEdge(this);
if (edge) {
Arrival arrival;
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
arc, edge, false, path_ap);
Arrival arrival = prev_arrival + arc_delay;
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
path->vertex(this)->to_string(this).c_str(),
path->tag(this)->to_string(this).c_str(),
delayAsString(path->arrival(), this),
delayAsString(arrival, this));
path->setArrival(arrival);
prev_arrival = arrival;
const Tag *tag = path->tag(this);
const ClkInfo *clk_info = tag->clkInfo();
if (crprActive()
&& clk_info != prev_clk_info
// D->Q paths use the EN->Q clk info so no need to update.
&& arc->role() != TimingRole::latchDtoQ()) {
// When crpr is enabled the diverion may be from another crpr clk pin,
// so update the tags to use the corresponding ClkInfo.
Tag *updated_tag = search_->findTag(path->transition(this),
path_ap,
prev_clk_info,
tag->isClock(),
tag->inputDelay(),
tag->isSegmentStart(),
tag->states(), false);
path->setTag(updated_tag);
const MinMax *min_max = path->minMax(this);
if (i == path_idx_max
&& edge->role()->isLatchDtoQ()
&& min_max == MinMax::max()) {
ArcDelay arc_delay;
Tag *q_tag;
latches_->latchOutArrival(after_div, arc, edge, path_ap,
q_tag, arc_delay, arrival);
path->setArrival(arrival);
path->setTag(q_tag);
prev_clk_info = q_tag->clkInfo();
}
else {
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
arc, edge, false, path_ap);
arrival = prev_arrival + arc_delay;
path->setArrival(arrival);
const Tag *tag = path->tag(this);
const ClkInfo *clk_info = tag->clkInfo();
if (crprActive()
&& clk_info != prev_clk_info
// D->Q paths use the EN->Q clk info so no need to update.
&& arc->role() != TimingRole::latchDtoQ()) {
// When crpr is enabled the diverion may be from another crpr clk pin,
// so update the tags to use the corresponding ClkInfo.
Tag *updated_tag = search_->findTag(path->transition(this),
path_ap,
prev_clk_info,
tag->isClock(),
tag->inputDelay(),
tag->isSegmentStart(),
tag->states(), false);
path->setTag(updated_tag);
}
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
path->vertex(this)->to_string(this).c_str(),
path->tag(this)->to_string(this).c_str(),
delayAsString(path->arrival(), this),
delayAsString(arrival, this));
}
prev_arrival = arrival;
}
}
}

View File

@ -546,8 +546,6 @@ PathGroups::makePathEnds(ExceptionTo *to,
pushGroupPathEnds(path_ends);
if (sort_by_slack) {
sort(path_ends, PathEndLess(this));
if (static_cast<int>(path_ends.size()) > group_path_count_)
path_ends.resize(group_path_count_);
}
if (unconstrained_paths

View File

@ -549,8 +549,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end) const
if (ignore_clk_latency) {
// Based on reportSrcPath.
reportPathHeader();
reportPath3(end->path(), expanded, false, false, 0.0,
end->sourceClkOffset(this));
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
}
else
reportSrcPath(end, expanded);
@ -716,8 +715,7 @@ ReportPath::reportFull(const PathEndPathDelay *end) const
if (end->ignoreClkLatency(this)) {
// Based on reportSrcPath.
reportPathHeader();
reportPath3(end->path(), expanded, false, false, 0.0,
end->sourceClkOffset(this));
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
}
else
reportSrcPath(end, expanded);
@ -935,11 +933,9 @@ ReportPath::reportFull(const PathEndDataCheck *end) const
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
float prev = delayAsFloat(clk_arrival) + src_offset;
float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time();
reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(),
clk_expanded.size() - 1,
data_clk_path->clkInfo(search_)->isPropagated(), false,
// Delay to startpoint is already included.
prev, offset);
// Delay to startpoint is already included.
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
true, false, prev, offset);
}
reportRequired(end, checkRoleReason(end));
reportSlack(end);
@ -1103,6 +1099,7 @@ ReportPath::reportJson(const PathEnd *end,
sdc_network_->pathName(endpoint));
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
const Path *src_clk_path = expanded.clkPath();
const Path *tgt_clk_path = end->targetClkPath();
if (src_clk_edge) {
stringAppend(result, " \"source_clock\": \"%s\",\n",
@ -1110,6 +1107,8 @@ ReportPath::reportJson(const PathEnd *end,
stringAppend(result, " \"source_clock_edge\": \"%s\",\n",
src_clk_edge->transition()->name());
}
if (src_clk_path)
reportJson(src_clk_path, "source_clock_path", 2, true, result);
reportJson(expanded, "source_path", 2, !end->isUnconstrained(), result);
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
@ -1180,7 +1179,7 @@ ReportPath::reportJson(const PathExpanded &expanded,
string &result) const
{
stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name);
for (size_t i = 0; i < expanded.size(); i++) {
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
const Path *path = expanded.path(i);
const Pin *pin = path->vertex(this)->pin();
const Net *net = network_->net(pin);
@ -1657,7 +1656,7 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
insertion, latency);
reportClkSrcLatency(insertion, clk_time, early_late);
PathExpanded clk_expanded(clk_path, this);
reportPath2(clk_path, clk_expanded, false, 0.0);
reportPath1(clk_path, clk_expanded, false, 0.0);
}
}
else {
@ -2226,8 +2225,8 @@ ReportPath::reportTgtClk(const PathEnd *end,
PathExpanded clk_expanded(clk_path, this);
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late,
path_ap);
reportPath5(clk_path, clk_expanded, 0, clk_expanded.size() - 1, is_prop,
reportClkPath(), delay_zero, time_offset + insertion_offset);
reportPath6(clk_path, clk_expanded, 0, is_prop, reportClkPath(),
delay_zero, time_offset + insertion_offset);
}
else {
// Output departure.
@ -2374,7 +2373,7 @@ ReportPath::reportGenClkSrcAndPath(const Path *path,
time_offset, clk_used_as_data);
if (path) {
PathExpanded expanded(path, this);
reportPath4(path, expanded, skip_first_path, false, clk_used_as_data,
reportPath2(path, expanded, skip_first_path, clk_used_as_data,
path_time_offset);
}
}
@ -2416,7 +2415,7 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
reportClkSrcLatency(insertion, gclk_time, early_late);
}
PathExpanded src_expanded(src_path, this);
reportPath4(src_path, src_expanded, skip_first_path, false,
reportPath2(src_path, src_expanded, skip_first_path,
clk_used_as_data, gclk_time);
if (!clk->isPropagated())
reportLine("clock network delay (ideal)", 0.0,
@ -2600,11 +2599,51 @@ ReportPath::reportPathFull(const Path *path) const
////////////////////////////////////////////////////////////////
// Main entry point for reporting a path.
void
ReportPath::reportPath1(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
float time_offset) const
{
reportPath2(path, expanded, false, clk_used_as_data, time_offset);
}
// Alternate entry point with skip_first_path arg.
void
ReportPath::reportPath2(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool clk_used_as_data,
float time_offset) const
{
bool clk_is_propagated = path->clkInfo(search_)->isPropagated();
bool report_clk_path = (reportClkPath() && clk_is_propagated)
|| clk_used_as_data;
bool propagated_clk = clk_is_propagated || clk_used_as_data;
reportPath4(path, expanded, skip_first_path, propagated_clk,
report_clk_path, time_offset);
}
// Alternate entry point with report_clk_path arg.
void
ReportPath::reportPath3(const Path *path,
const PathExpanded &expanded,
bool report_clk_path,
float time_offset) const
{
bool propagated_clk = path->clkInfo(search_)->isPropagated();
reportPath4(path, expanded, false, propagated_clk,
report_clk_path, time_offset);
}
void
ReportPath::reportPath4(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
{
const Path *d_path, *q_path;
Edge *d_q_edge;
@ -2617,11 +2656,11 @@ ReportPath::reportPath1(const Path *path,
if (latch_enable_path) {
const EarlyLate *early_late = latch_enable_path->minMax(this);
latch_enable_time = search_->clkPathArrival(latch_enable_path);
if (reportClkPath()) {
if (report_clk_path) {
PathExpanded enable_expanded(latch_enable_path, this);
// Report the path to the latch enable.
reportPath2(latch_enable_path, enable_expanded, false,
time_offset);
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
propagated_clk, report_clk_path, time_offset);
}
Arrival time = latch_enable_time + latch_time_given;
Arrival incr = latch_time_given;
@ -2631,86 +2670,45 @@ ReportPath::reportPath1(const Path *path,
reportLine("time borrowed from startpoint", incr, time, early_late);
// Override latch D arrival with enable + given.
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
bool propagated_clk = path->clkInfo(search_)->isPropagated();
bool report_clk_path = path->isClock(search_) || reportClkPath();
reportPath5(path, expanded, 1, expanded.size() - 1,
propagated_clk, report_clk_path,
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
latch_enable_time + latch_time_given, time_offset);
}
}
else
reportPath2(path, expanded, clk_used_as_data, time_offset);
}
void
ReportPath::reportPath2(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
float time_offset) const
{
// Report the clock path if the end is a clock or we wouldn't have
// anything to report.
bool report_clk_path = clk_used_as_data
|| (reportClkPath()
&& path->clkInfo(search_)->isPropagated());
reportPath3(path, expanded, clk_used_as_data, report_clk_path,
delay_zero, time_offset);
}
void
ReportPath::reportPath3(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool report_clk_path,
Arrival prev_time,
float time_offset) const
{
bool propagated_clk = clk_used_as_data
|| path->clkInfo(search_)->isPropagated();
size_t path_last_index = expanded.size() - 1;
reportPath5(path, expanded, 0, path_last_index, propagated_clk,
report_clk_path, prev_time, time_offset);
}
void
ReportPath::reportPath4(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool skip_last_path,
bool clk_used_as_data,
float time_offset) const
{
size_t path_first_index = 0;
Arrival prev_time(0.0);
if (skip_first_path) {
path_first_index = 1;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
}
size_t path_last_index = expanded.size() - 1;
if (skip_last_path
&& path_last_index > 1)
path_last_index--;
bool propagated_clk = clk_used_as_data
|| path->clkInfo(search_)->isPropagated();
// Report the clock path if the end is a clock or we wouldn't have
// anything to report.
bool report_clk_path = path->isClock(search_)
|| (reportClkPath() && propagated_clk);
reportPath5(path, expanded, path_first_index, path_last_index,
propagated_clk, report_clk_path, prev_time, time_offset);
reportPath5(path, expanded, skip_first_path, propagated_clk,
report_clk_path, time_offset);
}
void
ReportPath::reportPath5(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
{
size_t path_first_index = 0;
Arrival prev_time = 0.0;
if (skip_first_path) {
path_first_index = 1;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
}
reportPath6(path, expanded, path_first_index, propagated_clk,
report_clk_path, prev_time, time_offset);
}
// This does the real workk of reporting an expanded path.
void
ReportPath::reportPath6(const Path *path,
const PathExpanded &expanded,
size_t path_first_index,
size_t path_last_index,
bool propagated_clk,
bool report_clk_path,
Arrival prev_time,
float time_offset) const
{
size_t path_last_index = expanded.size() - 1;
const MinMax *min_max = path->minMax(this);
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
DcalcAPIndex ap_index = dcalc_ap->index();
@ -2986,8 +2984,7 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull() && reportClkPath()) {
PathExpanded ref_expanded(&ref_path, this);
reportPath3(&ref_path, ref_expanded, false, true,
delay_zero, 0.0);
reportPath3(&ref_path, ref_expanded, true, 0.0);
}
}
float input_arrival =

View File

@ -302,24 +302,28 @@ protected:
float time_offset) const;
void reportPath2(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool clk_used_as_data,
float time_offset) const;
void reportPath3(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool report_clk_path,
Arrival prev_time,
float time_offset) const;
void reportPath4(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool skip_first_path,
bool skip_last_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const;
void reportPath5(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const;
void reportPath6(const Path *path,
const PathExpanded &expanded,
size_t path_first_index,
size_t path_last_index,
bool propagated_clk,
bool report_clk_path,
Arrival prev_time,

View File

@ -429,8 +429,10 @@ Search::deletePaths(Vertex *vertex)
debugPrint(debug_, "search", 4, "delete paths %s",
vertex->name(network_));
TagGroup *tag_group = tagGroup(vertex);
if (tag_group)
if (tag_group) {
graph_->deletePaths(vertex);
tag_group->decrRefCount();
}
}
////////////////////////////////////////////////////////////////
@ -554,15 +556,20 @@ Search::deleteFilterTagGroups()
for (TagGroupIndex i = 0; i < tag_group_next_; i++) {
TagGroup *group = tag_groups_[i];
if (group
&& group->hasFilterTag()) {
tag_group_set_->erase(group);
tag_groups_[group->index()] = nullptr;
tag_group_free_indices_.push_back(i);
delete group;
}
&& group->hasFilterTag())
deleteTagGroup(group);
}
}
void
Search::deleteTagGroup(TagGroup *group)
{
tag_group_set_->erase(group);
tag_groups_[group->index()] = nullptr;
tag_group_free_indices_.push_back(group->index());
delete group;
}
void
Search::deleteFilterTags()
{
@ -628,6 +635,16 @@ Search::deleteTagsPrev()
tag_groups_prev_.clear();
}
void
Search::deleteUnusedTagGroups()
{
for (TagGroupIndex i = 0; i < tag_group_next_; i++) {
TagGroup *group = tag_groups_[i];
if (group && group->refCount() == 0)
deleteTagGroup(group);
}
}
VertexSeq
Search::filteredEndpoints()
{
@ -1057,6 +1074,7 @@ Search::findArrivals1(Level level)
Stats stats(debug_, report_);
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
deleteTagsPrev();
deleteUnusedTagGroups();
stats.report("Find arrivals");
if (arrival_iter_->empty()
&& invalid_arrivals_->empty()) {
@ -2222,7 +2240,8 @@ PathVisitor::visitFromPath(const Pin *from_pin,
}
}
else if (edge->role() == TimingRole::latchDtoQ()) {
if (min_max == MinMax::max()) {
if (min_max == MinMax::max()
&& clk) {
arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, path_ap);
latches_->latchOutArrival(from_path, arc, edge, path_ap,
to_tag, arc_delay, to_arrival);
@ -2751,31 +2770,25 @@ Search::setVertexArrivals(Vertex *vertex,
TagGroup *prev_tag_group = tagGroup(vertex);
Path *prev_paths = graph_->paths(vertex);
TagGroup *tag_group = findTagGroup(tag_bldr);
size_t path_count = tag_group->pathCount();
// Reuse path array if it is the same size.
if (prev_tag_group
&& path_count == prev_tag_group->pathCount()) {
if (tag_group == prev_tag_group) {
tag_bldr->copyPaths(tag_group, prev_paths);
vertex->setTagGroupIndex(tag_group->index());
if (tag_group->hasFilterTag()) {
LockGuard lock(filtered_arrivals_lock_);
filtered_arrivals_->insert(vertex);
}
requiredInvalid(vertex);
}
else {
if (prev_tag_group) {
graph_->deletePaths(vertex);
prev_tag_group->decrRefCount();
requiredInvalid(vertex);
}
size_t path_count = tag_group->pathCount();
Path *paths = graph_->makePaths(vertex, path_count);
tag_bldr->copyPaths(tag_group, paths);
vertex->setTagGroupIndex(tag_group->index());
if (tag_group->hasFilterTag()) {
LockGuard lock(filtered_arrivals_lock_);
filtered_arrivals_->insert(vertex);
}
tag_group->incrRefCount();
}
if (tag_group->hasFilterTag()) {
LockGuard lock(filtered_arrivals_lock_);
filtered_arrivals_->insert(vertex);
}
}
}
@ -2819,12 +2832,14 @@ ReportPathLess::operator()(const Path *path1,
}
void
Search::reportArrivals(Vertex *vertex) const
Search::reportArrivals(Vertex *vertex,
bool report_tag_index) const
{
report_->reportLine("Vertex %s", vertex->to_string(this).c_str());
TagGroup *tag_group = tagGroup(vertex);
if (tag_group) {
report_->reportLine("Group %u", tag_group->index());
if (report_tag_index)
report_->reportLine("Group %u", tag_group->index());
std::vector<const Path*> paths;
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
@ -2859,7 +2874,7 @@ Search::reportArrivals(Vertex *vertex) const
path_ap->pathMinMax()->to_string().c_str(),
delayAsString(path->arrival(), this),
req,
tag->to_string(true, false, this).c_str(),
tag->to_string(report_tag_index, false, this).c_str(),
prev_str.c_str());
}
}

View File

@ -252,7 +252,7 @@ vertex_worst_slack_path(Vertex *vertex,
}
int
tag_group_path_count()
tag_group_count()
{
return Sta::sta()->tagGroupCount();
}
@ -264,9 +264,10 @@ report_tag_groups()
}
void
report_tag_arrivals_cmd(Vertex *vertex)
report_tag_arrivals_cmd(Vertex *vertex,
bool report_tag_index)
{
Sta::sta()->search()->reportArrivals(vertex);
Sta::sta()->search()->reportArrivals(vertex, report_tag_index);
}
void

View File

@ -978,7 +978,7 @@ proc report_slack { pin } {
proc report_tag_arrivals { pin } {
set pin [get_port_pin_error "pin" $pin]
foreach vertex [$pin vertices] {
report_tag_arrivals_cmd $vertex
report_tag_arrivals_cmd $vertex 1
}
}

View File

@ -2963,6 +2963,7 @@ Sta::netSlack(const Net *net,
slack = pin_slack;
}
}
delete pin_iter;
return slack;
}

View File

@ -355,7 +355,7 @@ tagCmp(const Tag *tag1,
return tagStateCmp(tag1, tag2);
}
int
bool
tagEqual(const Tag *tag1,
const Tag *tag2)
{

View File

@ -140,6 +140,9 @@ public:
const Tag *tag2) const;
};
bool
tagEqual(const Tag *tag1,
const Tag *tag2);
int
tagCmp(const Tag *tag1,
const Tag *tag2,

View File

@ -44,6 +44,7 @@ TagGroup::TagGroup(TagGroupIndex index,
bool has_loop_tag) :
path_index_map_(path_index_map),
hash_(pathIndexMapHash(path_index_map)),
ref_count_(0),
index_(index),
has_clk_tag_(has_clk_tag),
has_genclk_src_tag_(has_genclk_src_tag),
@ -56,6 +57,7 @@ TagGroup::TagGroup(TagGroupIndex index,
TagGroup::TagGroup(TagGroupBldr *tag_bldr) :
path_index_map_(&tag_bldr->pathIndexMap()),
hash_(pathIndexMapHash(path_index_map_)),
ref_count_(0),
own_path_map_(false)
{
}
@ -66,6 +68,18 @@ TagGroup::~TagGroup()
delete path_index_map_;
}
void
TagGroup::incrRefCount()
{
ref_count_++;
}
void
TagGroup::decrRefCount()
{
ref_count_--;
}
size_t
TagGroup::pathIndexMapHash(PathIndexMap *path_index_map)
{

View File

@ -24,6 +24,8 @@
#pragma once
#include <atomic>
#include "Vector.hh"
#include "Map.hh"
#include "Iterator.hh"
@ -65,6 +67,9 @@ public:
size_t pathIndex(Tag *tag) const;
PathIndexMap *pathIndexMap() const { return path_index_map_; }
bool hasTag(Tag *tag) const;
void incrRefCount();
void decrRefCount();
int refCount() const { return ref_count_; }
protected:
static size_t pathIndexMapHash(PathIndexMap *path_index_map);
@ -72,6 +77,7 @@ protected:
// tag -> path index
PathIndexMap *path_index_map_;
size_t hash_;
std::atomic<int> ref_count_;
unsigned int index_:tag_group_index_bits;
bool has_clk_tag_:1;
bool has_genclk_src_tag_:1;

View File

@ -178,9 +178,6 @@ VisitPathEnds::visitCheckEnd(const Pin *pin,
&& tgt_clk != sdc_->defaultArrivalClock()
&& sdc_->sameClockGroup(src_clk, tgt_clk)
&& !sdc_->clkStopPropagation(tgt_pin, tgt_clk)
&& (search_->checkDefaultArrivalPaths()
|| src_clk_edge
!= sdc_->defaultArrivalClockEdge())
// False paths and path delays override
// paths.
&& (exception == nullptr
@ -360,9 +357,6 @@ VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay,
is_constrained = true;
}
else if (src_clk_edge
&& (search_->checkDefaultArrivalPaths()
|| src_clk_edge
!= sdc_->defaultArrivalClockEdge())
&& tgt_clk_edge
&& sdc_->sameClockGroup(path->clock(this), tgt_clk_edge->clock())
// False paths and path delays override.

View File

@ -156,6 +156,7 @@ record_sta_tests {
report_json2
suppress_msg
verilog_attribute
report_checks_sorted
}
define_test_group fast [group_tests all]

View File

@ -0,0 +1,87 @@
Startpoint: r1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: r4 (rising edge-triggered flip-flop clocked by clk)
Path Group: long
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ r1/CLK (DFFHQx4_ASAP7_75t_R)
64.76 64.76 ^ r1/Q (DFFHQx4_ASAP7_75t_R)
17.77 82.53 ^ u2/Y (BUFx2_ASAP7_75t_R)
17.88 100.42 ^ u3/Y (BUFx2_ASAP7_75t_R)
16.66 117.08 ^ u4/Y (BUFx2_ASAP7_75t_R)
0.00 117.08 ^ r4/D (DFFHQx4_ASAP7_75t_R)
117.08 data arrival time
500.00 500.00 clock clk (rise edge)
0.00 500.00 clock network delay (ideal)
0.00 500.00 clock reconvergence pessimism
500.00 ^ r4/CLK (DFFHQx4_ASAP7_75t_R)
-12.61 487.39 library setup time
487.39 data required time
---------------------------------------------------------
487.39 data required time
-117.08 data arrival time
---------------------------------------------------------
370.32 slack (MET)
Startpoint: r1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: r3 (rising edge-triggered flip-flop clocked by clk)
Path Group: custom
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ r1/CLK (DFFHQx4_ASAP7_75t_R)
64.76 64.76 ^ r1/Q (DFFHQx4_ASAP7_75t_R)
17.77 82.53 ^ u2/Y (BUFx2_ASAP7_75t_R)
17.88 100.42 ^ u3/Y (BUFx2_ASAP7_75t_R)
0.00 100.42 ^ r3/D (DFFHQx4_ASAP7_75t_R)
100.42 data arrival time
500.00 500.00 clock clk (rise edge)
0.00 500.00 clock network delay (ideal)
0.00 500.00 clock reconvergence pessimism
500.00 ^ r3/CLK (DFFHQx4_ASAP7_75t_R)
-12.98 487.02 library setup time
487.02 data required time
---------------------------------------------------------
487.02 data required time
-100.42 data arrival time
---------------------------------------------------------
386.60 slack (MET)
Startpoint: r1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: r2 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ r1/CLK (DFFHQx4_ASAP7_75t_R)
64.76 64.76 ^ r1/Q (DFFHQx4_ASAP7_75t_R)
17.77 82.53 ^ u2/Y (BUFx2_ASAP7_75t_R)
0.00 82.53 ^ r2/D (DFFHQx4_ASAP7_75t_R)
82.53 data arrival time
500.00 500.00 clock clk (rise edge)
0.00 500.00 clock network delay (ideal)
0.00 500.00 clock reconvergence pessimism
500.00 ^ r2/CLK (DFFHQx4_ASAP7_75t_R)
-12.98 487.02 library setup time
487.02 data required time
---------------------------------------------------------
487.02 data required time
-82.53 data arrival time
---------------------------------------------------------
404.48 slack (MET)

View File

@ -0,0 +1,12 @@
# report_checks with sorted path ends
read_liberty asap7_small.lib.gz
read_verilog report_checks_sorted.v
link_design top
create_clock -name clk -period 500 {clk}
set_input_delay -clock clk 0 {in}
group_path -name custom -to {r3}
group_path -name long -to {r4}
report_checks -group_path_count 1 -sort_by_slack

View File

@ -0,0 +1,15 @@
module top (input in, input clk, output out);
wire w1, w2, w3, w4;
DFFHQx4_ASAP7_75t_R r1 (.D(in), .CLK(clk), .Q(w1));
BUFx2_ASAP7_75t_R u2 (.A(w1), .Y(w2));
BUFx2_ASAP7_75t_R u3 (.A(w2), .Y(w3));
BUFx2_ASAP7_75t_R u4 (.A(w3), .Y(w4));
DFFHQx4_ASAP7_75t_R r2 (.D(w2), .CLK(clk), .Q(out));
DFFHQx4_ASAP7_75t_R r3 (.D(w3), .CLK(clk), .Q(out));
DFFHQx4_ASAP7_75t_R r4 (.D(w4), .CLK(clk), .Q(out));
endmodule

View File

@ -7,7 +7,7 @@
"endpoint": "_1416_[0]/D",
"source_clock": "clk",
"source_clock_edge": "rise",
"source_path": [
"source_clock_path": [
{
"instance": "",
"cell": "counter",
@ -25,7 +25,9 @@
"net": "clk",
"arrival": 0.000e+00,
"slew": 0.000e+00
},
}
],
"source_path": [
{
"instance": "_1415_",
"cell": "sky130_fd_sc_hd__dfrtp_1",

View File

@ -89,7 +89,9 @@ PatternMatch::compileRegexp()
anchored_pattern += '$';
Tcl_Obj *pattern_obj = Tcl_NewStringObj(anchored_pattern.c_str(),
anchored_pattern.size());
Tcl_IncrRefCount(pattern_obj);
regexp_ = Tcl_GetRegExpFromObj(interp_, pattern_obj, flags);
Tcl_DecrRefCount(pattern_obj);
if (regexp_ == nullptr && interp_)
throw RegexpCompileError(pattern_);
}

View File

@ -117,7 +117,7 @@ public:
int n_putback = gptr() - eback();
if ( n_putback > 4)
n_putback = 4;
memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback);
memmove( buffer + (4 - n_putback), gptr() - n_putback, n_putback);
int num = gzread( file, buffer+4, bufferSize-4);
if (num <= 0) // ERROR or EOF