Compare commits
34 Commits
5d5108e5db
...
89444a6111
| Author | SHA1 | Date |
|---|---|---|
|
|
89444a6111 | |
|
|
3b2961ebd2 | |
|
|
9870b14640 | |
|
|
30c8230f68 | |
|
|
2412feec33 | |
|
|
aa27e3372e | |
|
|
39fd453a69 | |
|
|
dcbaaf4c05 | |
|
|
26be60906c | |
|
|
2163a5c6b9 | |
|
|
433f9aa7d7 | |
|
|
5d02db77d7 | |
|
|
594537b719 | |
|
|
2a1e49e8f4 | |
|
|
774c3c68f1 | |
|
|
45a8a1bcc0 | |
|
|
1731dd0c38 | |
|
|
e475ee2c98 | |
|
|
849832a951 | |
|
|
e4a1ebf00e | |
|
|
5e1cecc38b | |
|
|
aaec7557dc | |
|
|
255988633f | |
|
|
b654fd48a8 | |
|
|
70f4bc0459 | |
|
|
872f611fea | |
|
|
5b56558e7a | |
|
|
4920f673a8 | |
|
|
0cd16e504a | |
|
|
d31e3b06e2 | |
|
|
6d18003c04 | |
|
|
82fd625199 | |
|
|
12f03395ec | |
|
|
335b305149 |
|
|
@ -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}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3904
doc/OpenSTA.fodt
3904
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -559,6 +559,8 @@ LibertyReader::defineVisitors()
|
|||
|
||||
defineGroupVisitor("ecsm_waveform", &LibertyReader::beginEcsmWaveform,
|
||||
&LibertyReader::endEcsmWaveform);
|
||||
defineGroupVisitor("ecsm_waveform_set", &LibertyReader::beginEcsmWaveform,
|
||||
&LibertyReader::endEcsmWaveform);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2963,6 +2963,7 @@ Sta::netSlack(const Net *net,
|
|||
slack = pin_slack;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
return slack;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ tagCmp(const Tag *tag1,
|
|||
return tagStateCmp(tag1, tag2);
|
||||
}
|
||||
|
||||
int
|
||||
bool
|
||||
tagEqual(const Tag *tag1,
|
||||
const Tag *tag2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ record_sta_tests {
|
|||
report_json2
|
||||
suppress_msg
|
||||
verilog_attribute
|
||||
report_checks_sorted
|
||||
}
|
||||
|
||||
define_test_group fast [group_tests all]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue