2018/11/08 corners > 2 causes internal error, 2018/11/09 Verilog ignore attributes (* blah *)
This commit is contained in:
parent
7592f12e54
commit
e9bde796ec
|
|
@ -412,7 +412,7 @@ AC_FUNC_ERROR_AT_LINE
|
|||
|
||||
if test $CXX = clang++; then
|
||||
# -Wno-deprecated-register to suppress warnings in flex files
|
||||
CXXFLAGS="-std=c++11 -Wno-deprecated-register -Wcast-qual -pipe"
|
||||
CXXFLAGS="-std=c++11 -Wall -Wno-deprecated-register -Wcast-qual"
|
||||
CXX_OPT="-O3"
|
||||
CXX_DEBUG="-g"
|
||||
CXX_ASAN="-fsanitize=address -O1 -fno-omit-frame-pointer"
|
||||
|
|
|
|||
|
|
@ -1202,7 +1202,7 @@ GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex,
|
|||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
if (!wire_edge->wireDelayAnnotated(tr, ap_index))
|
||||
if (!graph_->wireDelayAnnotated(wire_edge, tr, ap_index))
|
||||
graph_->setWireArcDelay(wire_edge, tr, ap_index, delay_init_value);
|
||||
// Init load vertex slew.
|
||||
if (init_load_slews
|
||||
|
|
@ -1274,7 +1274,7 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell,
|
|||
if (delayFuzzyGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax())
|
||||
&& !drvr_vertex->slewAnnotated(drvr_tr, ap_index))
|
||||
graph_->setSlew(drvr_vertex, drvr_tr, ap_index, gate_slew);
|
||||
if (!edge->arcDelayAnnotated(arc, ap_index)) {
|
||||
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
|
||||
const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
|
||||
float gate_delay1 = delayAsFloat(gate_delay);
|
||||
float prev_gate_delay1 = delayAsFloat(prev_gate_delay);
|
||||
|
|
@ -1486,7 +1486,7 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex,
|
|||
graph_->setSlew(load_vertex, drvr_tr, ap_index, load_slew);
|
||||
}
|
||||
}
|
||||
if (!wire_edge->wireDelayAnnotated(drvr_tr, ap_index)) {
|
||||
if (!graph_->wireDelayAnnotated(wire_edge, drvr_tr, ap_index)) {
|
||||
// Multiple timing arcs with the same output transition
|
||||
// annotate the same wire edges so they must be combined
|
||||
// rather than set.
|
||||
|
|
@ -1570,7 +1570,7 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge,
|
|||
while (ap_iter.hasNext()) {
|
||||
DcalcAnalysisPt *dcalc_ap = ap_iter.next();
|
||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||
if (!edge->arcDelayAnnotated(arc, ap_index)) {
|
||||
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
|
||||
const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax());
|
||||
if (pvt == NULL)
|
||||
pvt = dcalc_ap->operatingConditions();
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@ Release 2.0 Patches
|
|||
-------------------
|
||||
2018/10/23 spash msg embedded quotes seg fault
|
||||
2018/10/23 read_verilog mod inst with no ports seg fault
|
||||
2018/11/08 corners > 2 causes internal error
|
||||
2018/11/09 Verilog ignore attributes (* blah *)
|
||||
|
|
|
|||
151
graph/Graph.cc
151
graph/Graph.cc
|
|
@ -714,6 +714,9 @@ Graph::makeArcDelayPools(ArcIndex arc_count,
|
|||
DelayPool *pool = new DelayPool(arc_count);
|
||||
arc_delays_[i] = pool;
|
||||
}
|
||||
|
||||
unsigned annot_size = arc_count * 1.2;
|
||||
arc_delay_annotated_.resize(annot_size * ap_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -743,6 +746,13 @@ Graph::makeEdgeArcDelays(Edge *edge)
|
|||
*arc_delays++ = 0.0;
|
||||
}
|
||||
edge->setArcDelays(arc_index);
|
||||
// Make sure there is room for delay_annotated flags.
|
||||
unsigned max_annot_index = arc_index + (arc_count * ap_count_);
|
||||
if (max_annot_index >= arc_delay_annotated_.size()) {
|
||||
unsigned size = max_annot_index * 1.2;
|
||||
arc_delay_annotated_.resize(size);
|
||||
}
|
||||
removeDelayAnnotated(edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -817,6 +827,46 @@ Graph::setWireArcDelay(Edge *edge,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Graph::arcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
return arc_delay_annotated_[index];
|
||||
}
|
||||
|
||||
void
|
||||
Graph::setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated)
|
||||
{
|
||||
int index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
arc_delay_annotated_[index] = annotated;
|
||||
}
|
||||
|
||||
bool
|
||||
Graph::wireDelayAnnotated(Edge *edge,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
+ ap_index;
|
||||
return arc_delay_annotated_[index];
|
||||
}
|
||||
|
||||
void
|
||||
Graph::setWireDelayAnnotated(Edge *edge,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated)
|
||||
{
|
||||
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
+ ap_index;
|
||||
arc_delay_annotated_[index] = annotated;
|
||||
}
|
||||
|
||||
// This only gets called if the analysis type changes from single
|
||||
// to bc_wc/ocv or visa versa.
|
||||
void
|
||||
|
|
@ -846,11 +896,41 @@ Graph::removeDelays()
|
|||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
makeEdgeArcDelays(edge);
|
||||
edge->removeDelayAnnotated();
|
||||
removeDelayAnnotated(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Graph::removeDelayAnnotated(Edge *edge)
|
||||
{
|
||||
edge->setDelayAnnotationIsIncremental(false);
|
||||
TimingArcSet *arc_set = edge->timingArcSet();
|
||||
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
|
||||
while (arc_iter->hasNext()) {
|
||||
TimingArc *arc = arc_iter->next();
|
||||
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
|
||||
setArcDelayAnnotated(edge, arc, ap_index, false);
|
||||
}
|
||||
}
|
||||
delete arc_iter;
|
||||
}
|
||||
|
||||
bool
|
||||
Graph::delayAnnotated(Edge *edge)
|
||||
{
|
||||
TimingArcSet *arc_set = edge->timingArcSet();
|
||||
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
|
||||
while (arc_iter->hasNext()) {
|
||||
TimingArc *arc = arc_iter->next();
|
||||
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
|
||||
if (arcDelayAnnotated(edge, arc, ap_index))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Graph::makeSlewPools(VertexIndex vertex_count,
|
||||
DcalcAPIndex ap_count)
|
||||
|
|
@ -1019,7 +1099,7 @@ Graph::removeDelaySlewAnnotations()
|
|||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
edge->removeDelayAnnotated();
|
||||
removeDelayAnnotated(edge);
|
||||
}
|
||||
vertex->removeSlewAnnotated();
|
||||
}
|
||||
|
|
@ -1272,7 +1352,6 @@ Edge::init(VertexIndex from,
|
|||
vertex_out_prev_ = 0;
|
||||
is_bidirect_inst_path_ = false;
|
||||
is_bidirect_net_path_ = false;
|
||||
delay_annotated_ = false;
|
||||
delay_annotation_is_incremental_ = false;
|
||||
sim_timing_sense_ = timing_sense_unknown;
|
||||
is_disabled_constraint_ = false;
|
||||
|
|
@ -1292,62 +1371,6 @@ Edge::setArcDelays(ArcIndex arc_delays)
|
|||
arc_delays_ = arc_delays;
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::arcDelayAnnotated() const
|
||||
{
|
||||
return delay_annotated_ != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::arcDelayAnnotated(TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int bit_index = ap_index * arc_set_->arcCount() + arc->index();
|
||||
if (bit_index >= delay_annotation_bit_count)
|
||||
internalError("arc annotation bit index out of range");
|
||||
return (delay_annotated_ & (1 << bit_index)) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
Edge::setArcDelayAnnotated(bool annotated,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index)
|
||||
{
|
||||
int bit_index = ap_index * arc_set_->arcCount() + arc->index();
|
||||
if (bit_index >= delay_annotation_bit_count)
|
||||
internalError("arc annotation bit index out of range");
|
||||
if (annotated)
|
||||
delay_annotated_ |= (1 << bit_index);
|
||||
else
|
||||
delay_annotated_ &= ~(1 << bit_index);
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::wireDelayAnnotated(const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int bit_index = ap_index * TimingArcSet::wireArcCount()
|
||||
+ TimingArcSet::wireArcIndex(tr);
|
||||
if (bit_index >= delay_annotation_bit_count)
|
||||
internalError("arc annotation bit index out of range");
|
||||
return (delay_annotated_ & (1 << bit_index)) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
Edge::setWireDelayAnnotated(bool annotated,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index)
|
||||
{
|
||||
int bit_index = ap_index * TimingArcSet::wireArcCount()
|
||||
+ TimingArcSet::wireArcIndex(tr);
|
||||
if (bit_index >= delay_annotation_bit_count)
|
||||
internalError("arc annotation bit index out of range");
|
||||
if (annotated)
|
||||
delay_annotated_ |= (1 << bit_index);
|
||||
else
|
||||
delay_annotated_ &= ~(1 << bit_index);
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::delayAnnotationIsIncremental() const
|
||||
{
|
||||
|
|
@ -1357,19 +1380,9 @@ Edge::delayAnnotationIsIncremental() const
|
|||
void
|
||||
Edge::setDelayAnnotationIsIncremental(bool is_incr)
|
||||
{
|
||||
if (delay_annotated_ != 0
|
||||
&& is_incr != delay_annotation_is_incremental_)
|
||||
delay_annotated_ = 0;
|
||||
delay_annotation_is_incremental_ = is_incr;
|
||||
}
|
||||
|
||||
void
|
||||
Edge::removeDelayAnnotated()
|
||||
{
|
||||
delay_annotated_ = 0;
|
||||
delay_annotation_is_incremental_ = false;
|
||||
}
|
||||
|
||||
TimingRole *
|
||||
Edge::role() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -128,6 +128,23 @@ public:
|
|||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index,
|
||||
const ArcDelay &delay);
|
||||
// Is timing arc delay annotated.
|
||||
bool arcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const;
|
||||
void setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated);
|
||||
bool wireDelayAnnotated(Edge *edge,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index) const;
|
||||
void setWireDelayAnnotated(Edge *edge,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated);
|
||||
// True if any edge arc is annotated.
|
||||
bool delayAnnotated(Edge *edge);
|
||||
EdgeIndex edgeCount() { return edge_count_; }
|
||||
virtual ArcIndex arcCount() { return arc_count_; }
|
||||
|
||||
|
|
@ -205,6 +222,7 @@ protected:
|
|||
float *makeFloats(ObjectIndex count);
|
||||
void deleteFloats(float *floats,
|
||||
ObjectIndex count);
|
||||
void removeDelayAnnotated(Edge *edge);
|
||||
|
||||
VertexPool *vertices_;
|
||||
EdgePool *edges_;
|
||||
|
|
@ -216,6 +234,7 @@ protected:
|
|||
VertexIndex vertex_count_;
|
||||
EdgeIndex edge_count_;
|
||||
ArcIndex arc_count_;
|
||||
Vector<bool> arc_delay_annotated_;
|
||||
int slew_tr_count_;
|
||||
bool have_arc_delays_;
|
||||
DcalcAPIndex ap_count_;
|
||||
|
|
@ -339,11 +358,6 @@ private:
|
|||
friend class VertexOutEdgeIterator;
|
||||
};
|
||||
|
||||
#define max_dcalc_analysis_pt_count 4
|
||||
// One annotation bit per timing arc per delay calculation analysis point.
|
||||
#define delay_annotation_bit_count \
|
||||
((timing_arc_index_max + 1) * max_dcalc_analysis_pt_count)
|
||||
|
||||
// There is one Edge between each pair of pins that has a timing
|
||||
// path between them.
|
||||
class Edge
|
||||
|
|
@ -359,20 +373,6 @@ public:
|
|||
void setTimingArcSet(TimingArcSet *set);
|
||||
ArcIndex arcDelays() const { return arc_delays_; }
|
||||
void setArcDelays(ArcIndex arc_delays);
|
||||
// True if any timing arc delay is annotated.
|
||||
bool arcDelayAnnotated() const;
|
||||
// Is timing arc delay annotated.
|
||||
bool arcDelayAnnotated(TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const;
|
||||
void setArcDelayAnnotated(bool annotated,
|
||||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index);
|
||||
bool wireDelayAnnotated(const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index) const;
|
||||
void setWireDelayAnnotated(bool annotated,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index);
|
||||
void removeDelayAnnotated();
|
||||
bool delayAnnotationIsIncremental() const;
|
||||
void setDelayAnnotationIsIncremental(bool is_incr);
|
||||
// Edge is disabled by set_disable_timing constraint.
|
||||
|
|
@ -406,8 +406,6 @@ protected:
|
|||
VertexIndex vertex_out_next_; // Vertex out edges doubly linked list.
|
||||
VertexIndex vertex_out_prev_;
|
||||
ArcIndex arc_delays_;
|
||||
// Timing arcs with sdf annotation.
|
||||
unsigned int delay_annotated_:delay_annotation_bit_count;
|
||||
unsigned int delay_annotation_is_incremental_:1;
|
||||
unsigned int is_bidirect_inst_path_:1;
|
||||
unsigned int is_bidirect_net_path_:1;
|
||||
|
|
|
|||
|
|
@ -40,11 +40,6 @@ TransRiseFall::destroy()
|
|||
fall_ = NULL;
|
||||
}
|
||||
|
||||
TransRiseFall::~TransRiseFall()
|
||||
{
|
||||
stringDelete(short_name_);
|
||||
}
|
||||
|
||||
TransRiseFall::TransRiseFall(const char *name,
|
||||
const char *short_name,
|
||||
int sdf_triple_index) :
|
||||
|
|
@ -54,9 +49,15 @@ TransRiseFall::TransRiseFall(const char *name,
|
|||
{
|
||||
}
|
||||
|
||||
TransRiseFall::~TransRiseFall()
|
||||
{
|
||||
stringDelete(short_name_);
|
||||
}
|
||||
|
||||
void
|
||||
TransRiseFall::setShortName(const char *short_name)
|
||||
{
|
||||
stringDelete(short_name_);
|
||||
short_name_ = stringCopy(short_name);
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +153,11 @@ TransRiseFallBoth::TransRiseFallBoth(const char *name,
|
|||
{
|
||||
}
|
||||
|
||||
TransRiseFallBoth::~TransRiseFallBoth()
|
||||
{
|
||||
stringDelete(short_name_);
|
||||
}
|
||||
|
||||
TransRiseFallBoth *
|
||||
TransRiseFallBoth::find(const char *tr_str)
|
||||
{
|
||||
|
|
@ -185,6 +191,7 @@ TransRiseFallBoth::matches(const Transition *tr) const
|
|||
void
|
||||
TransRiseFallBoth::setShortName(const char *short_name)
|
||||
{
|
||||
stringDelete(short_name_);
|
||||
short_name_ = stringCopy(short_name);
|
||||
}
|
||||
|
||||
|
|
@ -289,6 +296,7 @@ Transition::asRiseFallBoth() const
|
|||
void
|
||||
Transition::setName(const char *name)
|
||||
{
|
||||
stringDelete(name_);
|
||||
name_ = stringCopy(name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ protected:
|
|||
const char *short_name,
|
||||
int sdf_triple_index,
|
||||
TransRiseFall *as_rise_fall);
|
||||
~TransRiseFallBoth();
|
||||
|
||||
const char *name_;
|
||||
const char *short_name_;
|
||||
|
|
|
|||
128
sdc/Sdc.cc
128
sdc/Sdc.cc
|
|
@ -98,6 +98,7 @@ Sdc::Sdc(StaState *sta) :
|
|||
clk_index_(0),
|
||||
clk_insertions_(NULL),
|
||||
clk_group_exclusions_(NULL),
|
||||
clk_group_same_(NULL),
|
||||
clk_sense_map_(network_),
|
||||
clk_gating_check_(NULL),
|
||||
input_delay_index_(0),
|
||||
|
|
@ -2082,6 +2083,7 @@ Sdc::ensureClkGroupExclusions()
|
|||
{
|
||||
if (clk_group_exclusions_ == NULL) {
|
||||
clk_group_exclusions_ = new ClockPairSet;
|
||||
clk_group_same_ = new ClockPairSet;
|
||||
ClockGroupsNameMap::Iterator groups_iter(clk_groups_name_map_);
|
||||
while (groups_iter.hasNext()) {
|
||||
ClockGroups *clk_groups = groups_iter.next();
|
||||
|
|
@ -2096,54 +2098,85 @@ Sdc::makeClkGroupExclusions(ClockGroups *clk_groups)
|
|||
if (!(clk_groups->asynchronous()
|
||||
&& clk_groups->allowPaths())) {
|
||||
ClockGroupSet *groups = clk_groups->groups();
|
||||
if (groups->size() == 1) {
|
||||
// If there is only one group all clocks not in the group
|
||||
// are excluded.
|
||||
ClockGroupSet::Iterator group_iter1(groups);
|
||||
ClockGroup *group1 = group_iter1.next();
|
||||
ClockSet *clks1 = group1->clks();
|
||||
ClockSet::Iterator clk_iter1(clks1);
|
||||
while (clk_iter1.hasNext()) {
|
||||
Clock *clk1 = clk_iter1.next();
|
||||
ClockIterator *clk_iter2 = clockIterator();
|
||||
while (clk_iter2->hasNext()) {
|
||||
Clock *clk2 = clk_iter2->next();
|
||||
if (clk2 != clk1
|
||||
&& !group1->isMember(clk2)) {
|
||||
ClockPair *clk_pair = new ClockPair(clk1, clk2);
|
||||
clk_group_exclusions_->insert(clk_pair);
|
||||
}
|
||||
}
|
||||
delete clk_iter2;
|
||||
if (groups->size() == 1)
|
||||
makeClkGroupExclusions1(groups);
|
||||
else
|
||||
makeClkGroupExclusions(groups);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is only one group all clocks not in the group
|
||||
// are excluded.
|
||||
void
|
||||
Sdc::makeClkGroupExclusions1(ClockGroupSet *groups)
|
||||
{
|
||||
ClockGroupSet::Iterator group_iter1(groups);
|
||||
ClockGroup *group1 = group_iter1.next();
|
||||
ClockSet *clks1 = group1->clks();
|
||||
ClockSet::Iterator clk_iter1(clks1);
|
||||
while (clk_iter1.hasNext()) {
|
||||
Clock *clk1 = clk_iter1.next();
|
||||
ClockIterator *clk_iter2 = clockIterator();
|
||||
while (clk_iter2->hasNext()) {
|
||||
Clock *clk2 = clk_iter2->next();
|
||||
if (clk2 != clk1
|
||||
&& !group1->isMember(clk2)) {
|
||||
ClockPair *clk_pair = new ClockPair(clk1, clk2);
|
||||
clk_group_exclusions_->insert(clk_pair);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ClockGroupSet::Iterator group_iter1(groups);
|
||||
while (group_iter1.hasNext()) {
|
||||
ClockGroup *group1 = group_iter1.next();
|
||||
ClockGroupSet::Iterator group_iter2(groups);
|
||||
while (group_iter2.hasNext()) {
|
||||
ClockGroup *group2 = group_iter2.next();
|
||||
if (group1 != group2) {
|
||||
ClockSet *clks1 = group1->clks();
|
||||
ClockSet *clks2 = group2->clks();
|
||||
ClockSet::Iterator clk_iter1(clks1);
|
||||
while (clk_iter1.hasNext()) {
|
||||
Clock *clk1 = clk_iter1.next();
|
||||
ClockSet::Iterator clk_iter2(clks2);
|
||||
while (clk_iter2.hasNext()) {
|
||||
Clock *clk2 = clk_iter2.next();
|
||||
// ClockPair is symmetric so only add one clk1/clk2 pair.
|
||||
if (clk1->index() < clk2->index()) {
|
||||
ClockPair *clk_pair = new ClockPair(clk1, clk2);
|
||||
clk_group_exclusions_->insert(clk_pair);
|
||||
}
|
||||
}
|
||||
delete clk_iter2;
|
||||
}
|
||||
makeClkGroupSame(group1);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::makeClkGroupExclusions(ClockGroupSet *groups)
|
||||
{
|
||||
ClockGroupSet::Iterator group_iter1(groups);
|
||||
while (group_iter1.hasNext()) {
|
||||
ClockGroup *group1 = group_iter1.next();
|
||||
ClockSet *clks1 = group1->clks();
|
||||
ClockGroupSet::Iterator group_iter2(groups);
|
||||
while (group_iter2.hasNext()) {
|
||||
ClockGroup *group2 = group_iter2.next();
|
||||
if (group1 != group2) {
|
||||
ClockSet *clks2 = group2->clks();
|
||||
ClockSet::Iterator clk_iter1(clks1);
|
||||
while (clk_iter1.hasNext()) {
|
||||
Clock *clk1 = clk_iter1.next();
|
||||
ClockSet::Iterator clk_iter2(clks2);
|
||||
while (clk_iter2.hasNext()) {
|
||||
Clock *clk2 = clk_iter2.next();
|
||||
// ClockPair is symmetric so only add one clk1/clk2 pair.
|
||||
if (clk1->index() < clk2->index()) {
|
||||
ClockPair *clk_pair = new ClockPair(clk1, clk2);
|
||||
clk_group_exclusions_->insert(clk_pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeClkGroupSame(group1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::makeClkGroupSame(ClockGroup *group)
|
||||
{
|
||||
ClockSet *clks = group->clks();
|
||||
ClockSet::Iterator clk_iter1(clks);
|
||||
while (clk_iter1.hasNext()) {
|
||||
Clock *clk1 = clk_iter1.next();
|
||||
ClockSet::Iterator clk_iter2(clks);
|
||||
while (clk_iter2.hasNext()) {
|
||||
Clock *clk2 = clk_iter2.next();
|
||||
if (clk1->index() <= clk2->index()) {
|
||||
ClockPair *clk_pair = new ClockPair(clk1, clk2);
|
||||
if (!clk_group_same_->hasKey(clk_pair))
|
||||
clk_group_same_->insert(clk_pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2152,14 +2185,17 @@ Sdc::clearClkGroupExclusions()
|
|||
{
|
||||
if (clk_group_exclusions_) {
|
||||
clk_group_exclusions_->deleteContents();
|
||||
clk_group_same_->deleteContents();
|
||||
delete clk_group_exclusions_;
|
||||
delete clk_group_same_;
|
||||
clk_group_exclusions_ = NULL;
|
||||
clk_group_same_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Sdc::sameClockGroup(const Clock *clk1,
|
||||
const Clock *clk2)
|
||||
const Clock *clk2)
|
||||
{
|
||||
if (clk1 && clk2) {
|
||||
ClockPair clk_pair(clk1, clk2);
|
||||
|
|
@ -2170,6 +2206,14 @@ Sdc::sameClockGroup(const Clock *clk1,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Sdc::sameClockGroupExplicit(const Clock *clk1,
|
||||
const Clock *clk2)
|
||||
{
|
||||
ClockPair clk_pair(clk1, clk2);
|
||||
return clk_group_same_->hasKey(&clk_pair);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::removeClockGroups(const char *name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,9 @@ public:
|
|||
void removeClockGroupsAsynchronous(const char *name);
|
||||
bool sameClockGroup(const Clock *clk1,
|
||||
const Clock *clk2);
|
||||
// Clocks explicitly excluded by set_clock_group.
|
||||
bool sameClockGroupExplicit(const Clock *clk1,
|
||||
const Clock *clk2);
|
||||
void setClockSense(PinSet *pins,
|
||||
ClockSet *clks,
|
||||
ClockSense sense);
|
||||
|
|
@ -1250,6 +1253,9 @@ protected:
|
|||
void removeClockGroups(ClockGroups *groups);
|
||||
void ensureClkGroupExclusions();;
|
||||
void makeClkGroupExclusions(ClockGroups *clk_groups);
|
||||
void makeClkGroupExclusions1(ClockGroupSet *groups);
|
||||
void makeClkGroupExclusions(ClockGroupSet *groups);
|
||||
void makeClkGroupSame(ClockGroup *group);
|
||||
void clearClkGroupExclusions();
|
||||
char *makeClockGroupsName();
|
||||
void setClockSense(const Pin *pin,
|
||||
|
|
@ -1298,6 +1304,8 @@ protected:
|
|||
ClockGroupsNameMap clk_groups_name_map_;
|
||||
// clk to clk paths excluded by clock groups.
|
||||
ClockPairSet *clk_group_exclusions_;
|
||||
// clks in the same set_clock_group set.
|
||||
ClockPairSet *clk_group_same_;
|
||||
ClockSenseMap clk_sense_map_;
|
||||
ClockGatingCheck *clk_gating_check_;
|
||||
ClockGatingCheckMap clk_gating_check_map_;
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ ReportAnnotated::findCounts()
|
|||
LogicValue from_logic_value;
|
||||
bool from_logic_value_exists;
|
||||
sdc_->logicValue(from_pin, from_logic_value,
|
||||
from_logic_value_exists);
|
||||
from_logic_value_exists);
|
||||
VertexOutEdgeIterator edge_iter(from_vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
|
|
@ -327,14 +327,14 @@ ReportAnnotated::findCounts()
|
|||
LogicValue to_logic_value;
|
||||
bool to_logic_value_exists;
|
||||
sdc_->logicValue(to_pin, to_logic_value,
|
||||
to_logic_value_exists);
|
||||
to_logic_value_exists);
|
||||
|
||||
edge_count_[index]++;
|
||||
|
||||
if (from_logic_value_exists || to_logic_value_exists)
|
||||
edge_constant_count_[index]++;
|
||||
if (report_role_[index]) {
|
||||
if (edge->arcDelayAnnotated()) {
|
||||
if (graph_->delayAnnotated(edge)) {
|
||||
edge_annotated_count_[index]++;
|
||||
if (from_logic_value_exists || to_logic_value_exists)
|
||||
edge_constant_annotated_count_[index]++;
|
||||
|
|
@ -501,7 +501,7 @@ ReportAnnotated::reportArcs(Vertex *vertex,
|
|||
Edge *edge = edge_iter.next();
|
||||
TimingRole *role = edge->role();
|
||||
const Pin *to_pin = edge->to(graph_)->pin();
|
||||
if (edge->arcDelayAnnotated() == report_annotated
|
||||
if (graph_->delayAnnotated(edge) == report_annotated
|
||||
&& report_role_[roleIndex(role, from_pin, to_pin)]) {
|
||||
const char *role_name;
|
||||
if (role->isTimingCheck())
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ SdfReader::setEdgeArcDelays(Edge *edge,
|
|||
else
|
||||
delay = *value_ptr;
|
||||
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
|
||||
edge->setArcDelayAnnotated(true, arc, arc_delay_index);
|
||||
graph_->setArcDelayAnnotated(edge, arc, arc_delay_index, true);
|
||||
edge->setDelayAnnotationIsIncremental(is_incremental_only_);
|
||||
}
|
||||
}
|
||||
|
|
@ -809,13 +809,13 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
|
|||
ArcDelay delay(*value);
|
||||
if (!is_incremental_only_ && in_incremental_)
|
||||
delay = graph_->arcDelay(edge, arc, arc_delay_index) + *value;
|
||||
else if (edge->arcDelayAnnotated(arc, arc_delay_index)) {
|
||||
else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) {
|
||||
ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index);
|
||||
if (delayFuzzyGreater(prev_value, delay, min_max))
|
||||
delay = prev_value;
|
||||
}
|
||||
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
|
||||
edge->setArcDelayAnnotated(true, arc, arc_delay_index);
|
||||
graph_->setArcDelayAnnotated(edge, arc, arc_delay_index, true);
|
||||
edge->setDelayAnnotationIsIncremental(is_incremental_only_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,17 +61,21 @@ CheckMinPeriods::clear()
|
|||
class MinPeriodViolatorsVisitor : public MinPeriodCheckVisitor
|
||||
{
|
||||
public:
|
||||
MinPeriodViolatorsVisitor(MinPeriodCheckSeq &checks);
|
||||
MinPeriodViolatorsVisitor(const Corner *corner,
|
||||
MinPeriodCheckSeq &checks);
|
||||
virtual void visit(MinPeriodCheck &check,
|
||||
StaState *sta);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPeriodViolatorsVisitor);
|
||||
|
||||
const Corner *corner_;
|
||||
MinPeriodCheckSeq &checks_;
|
||||
};
|
||||
|
||||
MinPeriodViolatorsVisitor::MinPeriodViolatorsVisitor(MinPeriodCheckSeq &checks):
|
||||
MinPeriodViolatorsVisitor::MinPeriodViolatorsVisitor(const Corner *corner,
|
||||
MinPeriodCheckSeq &checks):
|
||||
corner_(corner),
|
||||
checks_(checks)
|
||||
{
|
||||
}
|
||||
|
|
@ -85,10 +89,10 @@ MinPeriodViolatorsVisitor::visit(MinPeriodCheck &check,
|
|||
}
|
||||
|
||||
MinPeriodCheckSeq &
|
||||
CheckMinPeriods::violations()
|
||||
CheckMinPeriods::violations(const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
MinPeriodViolatorsVisitor visitor(checks_);
|
||||
MinPeriodViolatorsVisitor visitor(corner, checks_);
|
||||
visitMinPeriodChecks(&visitor);
|
||||
sort(checks_, MinPeriodSlackLess(sta_));
|
||||
return checks_;
|
||||
|
|
@ -128,10 +132,12 @@ CheckMinPeriods::visitMinPeriodChecks(Vertex *vertex,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class MinPeriodSlackVisitor : public MinPeriodCheckVisitor
|
||||
{
|
||||
public:
|
||||
MinPeriodSlackVisitor();
|
||||
MinPeriodSlackVisitor(const Corner *corner);
|
||||
virtual void visit(MinPeriodCheck &check,
|
||||
StaState *sta);
|
||||
MinPeriodCheck *minSlackCheck();
|
||||
|
|
@ -139,10 +145,12 @@ public:
|
|||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPeriodSlackVisitor);
|
||||
|
||||
const Corner *corner_;
|
||||
MinPeriodCheck *min_slack_check_;
|
||||
};
|
||||
|
||||
MinPeriodSlackVisitor::MinPeriodSlackVisitor() :
|
||||
MinPeriodSlackVisitor::MinPeriodSlackVisitor(const Corner *corner) :
|
||||
corner_(corner),
|
||||
min_slack_check_(NULL)
|
||||
{
|
||||
}
|
||||
|
|
@ -167,10 +175,10 @@ MinPeriodSlackVisitor::minSlackCheck()
|
|||
}
|
||||
|
||||
MinPeriodCheck *
|
||||
CheckMinPeriods::minSlackCheck()
|
||||
CheckMinPeriods::minSlackCheck(const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
MinPeriodSlackVisitor visitor;
|
||||
MinPeriodSlackVisitor visitor(corner);
|
||||
visitMinPeriodChecks(&visitor);
|
||||
MinPeriodCheck *check = visitor.minSlackCheck();
|
||||
// Save check for cleanup.
|
||||
|
|
|
|||
|
|
@ -36,9 +36,11 @@ public:
|
|||
~CheckMinPeriods();
|
||||
void clear();
|
||||
// All violating min period checks.
|
||||
MinPeriodCheckSeq &violations();
|
||||
// corner=NULL checks all corners.
|
||||
MinPeriodCheckSeq &violations(const Corner *corner);
|
||||
// Min period check with the least slack.
|
||||
MinPeriodCheck *minSlackCheck();
|
||||
// corner=NULL checks all corners.
|
||||
MinPeriodCheck *minSlackCheck(const Corner *corner);
|
||||
|
||||
protected:
|
||||
void visitMinPeriodChecks(MinPeriodCheckVisitor *visitor);
|
||||
|
|
|
|||
|
|
@ -74,49 +74,59 @@ CheckMinPulseWidths::clear()
|
|||
checks_.deleteContentsClear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class MinPulseWidthChecksVisitor : public MinPulseWidthCheckVisitor
|
||||
{
|
||||
public:
|
||||
explicit MinPulseWidthChecksVisitor(MinPulseWidthCheckSeq &checks);
|
||||
explicit MinPulseWidthChecksVisitor(const Corner *corner,
|
||||
MinPulseWidthCheckSeq &checks);
|
||||
virtual void visit(MinPulseWidthCheck &check,
|
||||
const StaState *sta);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPulseWidthChecksVisitor);
|
||||
|
||||
const Corner *corner_;
|
||||
MinPulseWidthCheckSeq &checks_;
|
||||
};
|
||||
|
||||
MinPulseWidthChecksVisitor::
|
||||
MinPulseWidthChecksVisitor(MinPulseWidthCheckSeq &checks) :
|
||||
MinPulseWidthChecksVisitor(const Corner *corner,
|
||||
MinPulseWidthCheckSeq &checks) :
|
||||
corner_(corner),
|
||||
checks_(checks)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MinPulseWidthChecksVisitor::visit(MinPulseWidthCheck &check,
|
||||
const StaState *)
|
||||
const StaState *sta)
|
||||
{
|
||||
MinPulseWidthCheck *copy = new MinPulseWidthCheck(check.openPath());
|
||||
checks_.push_back(copy);
|
||||
if (corner_ == NULL
|
||||
|| check.corner(sta) == corner_) {
|
||||
MinPulseWidthCheck *copy = new MinPulseWidthCheck(check.openPath());
|
||||
checks_.push_back(copy);
|
||||
}
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
CheckMinPulseWidths::check()
|
||||
CheckMinPulseWidths::check(const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
MinPulseWidthChecksVisitor visitor(checks_);
|
||||
MinPulseWidthChecksVisitor visitor(corner, checks_);
|
||||
visitMinPulseWidthChecks(&visitor);
|
||||
sort(checks_, MinPulseWidthSlackLess(sta_));
|
||||
return checks_;
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
CheckMinPulseWidths::check(PinSeq *pins)
|
||||
CheckMinPulseWidths::check(PinSeq *pins,
|
||||
const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
Graph *graph = sta_->graph();
|
||||
MinPulseWidthChecksVisitor visitor(checks_);
|
||||
MinPulseWidthChecksVisitor visitor(corner, checks_);
|
||||
PinSeq::Iterator pin_iter(pins);
|
||||
while (pin_iter.hasNext()) {
|
||||
Pin *pin = pin_iter.next();
|
||||
|
|
@ -127,49 +137,59 @@ CheckMinPulseWidths::check(PinSeq *pins)
|
|||
return checks_;
|
||||
}
|
||||
|
||||
class MinPulseWidthViolatorsVisititor : public MinPulseWidthCheckVisitor
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class MinPulseWidthViolatorsVisitor : public MinPulseWidthCheckVisitor
|
||||
{
|
||||
public:
|
||||
explicit MinPulseWidthViolatorsVisititor(MinPulseWidthCheckSeq &checks);
|
||||
explicit MinPulseWidthViolatorsVisitor(const Corner *corner,
|
||||
MinPulseWidthCheckSeq &checks);
|
||||
virtual void visit(MinPulseWidthCheck &check,
|
||||
const StaState *sta);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPulseWidthViolatorsVisititor);
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPulseWidthViolatorsVisitor);
|
||||
|
||||
const Corner *corner_;
|
||||
MinPulseWidthCheckSeq &checks_;
|
||||
};
|
||||
|
||||
MinPulseWidthViolatorsVisititor::
|
||||
MinPulseWidthViolatorsVisititor(MinPulseWidthCheckSeq &checks) :
|
||||
MinPulseWidthViolatorsVisitor::
|
||||
MinPulseWidthViolatorsVisitor(const Corner *corner,
|
||||
MinPulseWidthCheckSeq &checks) :
|
||||
corner_(corner),
|
||||
checks_(checks)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MinPulseWidthViolatorsVisititor::visit(MinPulseWidthCheck &check,
|
||||
const StaState *sta)
|
||||
MinPulseWidthViolatorsVisitor::visit(MinPulseWidthCheck &check,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (delayFuzzyLess(check.slack(sta), 0.0)) {
|
||||
if (delayFuzzyLess(check.slack(sta), 0.0)
|
||||
&& (corner_ == NULL
|
||||
|| check.corner(sta) == corner_)) {
|
||||
MinPulseWidthCheck *copy = new MinPulseWidthCheck(check.openPath());
|
||||
checks_.push_back(copy);
|
||||
}
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
CheckMinPulseWidths::violations()
|
||||
CheckMinPulseWidths::violations(const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
MinPulseWidthViolatorsVisititor visitor(checks_);
|
||||
MinPulseWidthViolatorsVisitor visitor(corner, checks_);
|
||||
visitMinPulseWidthChecks(&visitor);
|
||||
sort(checks_, MinPulseWidthSlackLess(sta_));
|
||||
return checks_;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class MinPulseWidthSlackVisitor : public MinPulseWidthCheckVisitor
|
||||
{
|
||||
public:
|
||||
MinPulseWidthSlackVisitor();
|
||||
MinPulseWidthSlackVisitor(const Corner *corner);
|
||||
virtual void visit(MinPulseWidthCheck &check,
|
||||
const StaState *sta);
|
||||
MinPulseWidthCheck *minSlackCheck();
|
||||
|
|
@ -177,10 +197,12 @@ public:
|
|||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MinPulseWidthSlackVisitor);
|
||||
|
||||
const Corner *corner_;
|
||||
MinPulseWidthCheck *min_slack_check_;
|
||||
};
|
||||
|
||||
MinPulseWidthSlackVisitor::MinPulseWidthSlackVisitor() :
|
||||
MinPulseWidthSlackVisitor::MinPulseWidthSlackVisitor(const Corner *corner) :
|
||||
corner_(corner),
|
||||
min_slack_check_(NULL)
|
||||
{
|
||||
}
|
||||
|
|
@ -190,11 +212,14 @@ MinPulseWidthSlackVisitor::visit(MinPulseWidthCheck &check,
|
|||
const StaState *sta)
|
||||
{
|
||||
MinPulseWidthSlackLess slack_less(sta);
|
||||
if (min_slack_check_ == NULL)
|
||||
min_slack_check_ = check.copy();
|
||||
else if (slack_less(&check, min_slack_check_)) {
|
||||
delete min_slack_check_;
|
||||
min_slack_check_ = check.copy();
|
||||
if (corner_ == NULL
|
||||
|| check.corner(sta) == corner_) {
|
||||
if (min_slack_check_ == NULL)
|
||||
min_slack_check_ = check.copy();
|
||||
else if (slack_less(&check, min_slack_check_)) {
|
||||
delete min_slack_check_;
|
||||
min_slack_check_ = check.copy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +230,10 @@ MinPulseWidthSlackVisitor::minSlackCheck()
|
|||
}
|
||||
|
||||
MinPulseWidthCheck *
|
||||
CheckMinPulseWidths::minSlackCheck()
|
||||
CheckMinPulseWidths::minSlackCheck(const Corner *corner)
|
||||
{
|
||||
clear();
|
||||
MinPulseWidthSlackVisitor visitor;
|
||||
MinPulseWidthSlackVisitor visitor(corner);
|
||||
visitMinPulseWidthChecks(&visitor);
|
||||
MinPulseWidthCheck *check = visitor.minSlackCheck();
|
||||
// Save check for cleanup.
|
||||
|
|
@ -452,6 +477,12 @@ MinPulseWidthCheck::slack(const StaState *sta) const
|
|||
return width(sta) - minWidth(sta);
|
||||
}
|
||||
|
||||
Corner *
|
||||
MinPulseWidthCheck::corner(const StaState *sta) const
|
||||
{
|
||||
return open_path_.pathAnalysisPt(sta)->corner();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
MinPulseWidthSlackLess::MinPulseWidthSlackLess(const StaState *sta) :
|
||||
|
|
|
|||
|
|
@ -36,13 +36,18 @@ public:
|
|||
~CheckMinPulseWidths();
|
||||
void clear();
|
||||
// Min pulse width checks for pins.
|
||||
MinPulseWidthCheckSeq &check(PinSeq *pins);
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &check(PinSeq *pins,
|
||||
const Corner *corner);
|
||||
// All min pulse width checks.
|
||||
MinPulseWidthCheckSeq &check();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &check(const Corner *corner);
|
||||
// All violating min pulse width checks.
|
||||
MinPulseWidthCheckSeq &violations();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &violations(const Corner *corner);
|
||||
// Min pulse width check with the least slack.
|
||||
MinPulseWidthCheck *minSlackCheck();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheck *minSlackCheck(const Corner *corner);
|
||||
|
||||
protected:
|
||||
void visitMinPulseWidthChecks(MinPulseWidthCheckVisitor *visitor);
|
||||
|
|
@ -68,6 +73,7 @@ public:
|
|||
float minWidth(const StaState *sta) const;
|
||||
Slack slack(const StaState *sta) const;
|
||||
Path *openPath() { return &open_path_; }
|
||||
Corner *corner(const StaState *sta) const;
|
||||
const Path *openPath() const { return &open_path_; }
|
||||
Arrival openArrival(const StaState *sta) const;
|
||||
void closePath(const StaState *sta,
|
||||
|
|
|
|||
|
|
@ -32,22 +32,26 @@ namespace sta {
|
|||
class PinSlewLimitSlackLess
|
||||
{
|
||||
public:
|
||||
PinSlewLimitSlackLess(const MinMax *min_max,
|
||||
PinSlewLimitSlackLess(const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
CheckSlewLimits *check_slew_limit,
|
||||
const StaState *sta);
|
||||
bool operator()(Pin *pin1,
|
||||
Pin *pin2) const;
|
||||
|
||||
private:
|
||||
const Corner *corner_;
|
||||
const MinMax *min_max_;
|
||||
CheckSlewLimits *check_slew_limit_;
|
||||
const StaState *sta_;
|
||||
|
||||
};
|
||||
|
||||
PinSlewLimitSlackLess::PinSlewLimitSlackLess(const MinMax *min_max,
|
||||
PinSlewLimitSlackLess::PinSlewLimitSlackLess(const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
CheckSlewLimits *check_slew_limit,
|
||||
const StaState *sta) :
|
||||
corner_(corner),
|
||||
min_max_(min_max),
|
||||
check_slew_limit_(check_slew_limit),
|
||||
sta_(sta)
|
||||
|
|
@ -62,9 +66,9 @@ PinSlewLimitSlackLess::operator()(Pin *pin1,
|
|||
const TransRiseFall *tr1, *tr2;
|
||||
Slew slew1, slew2;
|
||||
float limit1, limit2, slack1, slack2;
|
||||
check_slew_limit_->checkSlews(pin1, min_max_,
|
||||
check_slew_limit_->checkSlews(pin1, corner_, min_max_,
|
||||
corner1, tr1, slew1, limit1, slack1);
|
||||
check_slew_limit_->checkSlews(pin2, min_max_,
|
||||
check_slew_limit_->checkSlews(pin2, corner_, min_max_,
|
||||
corner2, tr2, slew2, limit2, slack2);
|
||||
return slack1 < slack2
|
||||
|| (fuzzyEqual(slack1, slack2)
|
||||
|
|
@ -94,41 +98,71 @@ CheckSlewLimits::init(const MinMax *min_max)
|
|||
|
||||
void
|
||||
CheckSlewLimits::checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
// Return the min slack transition.
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
corner = NULL;
|
||||
corner1 = NULL;
|
||||
tr = NULL;
|
||||
slack = MinMax::min()->initValue();
|
||||
if (corner)
|
||||
checkSlews1(pin, corner, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
else {
|
||||
CornerIterator corner_iter(sta_);
|
||||
while (corner_iter.hasNext()) {
|
||||
const Corner *corner2 = corner_iter.next();
|
||||
checkSlews1(pin, corner2, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::checkSlews1(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
Vertex *vertex, *bidirect_drvr_vertex;
|
||||
sta_->graph()->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
checkSlews1(vertex, corner, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
if (bidirect_drvr_vertex)
|
||||
checkSlews1(bidirect_drvr_vertex, corner, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::checkSlews1(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr1 = tr_iter.next();
|
||||
float limit1;
|
||||
bool limit1_exists;
|
||||
findLimit(pin, vertex, tr1, min_max, limit1, limit1_exists);
|
||||
findLimit(vertex->pin(), vertex, tr1, min_max, limit1, limit1_exists);
|
||||
if (limit1_exists) {
|
||||
CornerIterator corner_iter(sta_);
|
||||
while (corner_iter.hasNext()) {
|
||||
Corner *corner1 = corner_iter.next();
|
||||
checkSlew(vertex, limit1, tr1, corner1, min_max,
|
||||
corner, tr, slew, slack, limit);
|
||||
if (bidirect_drvr_vertex) {
|
||||
findLimit(pin, bidirect_drvr_vertex, tr1, min_max,
|
||||
limit1, limit1_exists);
|
||||
if (limit1_exists) {
|
||||
checkSlew(bidirect_drvr_vertex, limit1, tr1, corner1, min_max,
|
||||
corner, tr, slew, slack, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkSlew(vertex, corner1, min_max, tr1, limit1,
|
||||
corner, tr, slew, slack, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -229,10 +263,10 @@ CheckSlewLimits::clockDomains(const Vertex *vertex,
|
|||
|
||||
void
|
||||
CheckSlewLimits::checkSlew(Vertex *vertex,
|
||||
float limit1,
|
||||
const TransRiseFall *tr1,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
const TransRiseFall *tr1,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const TransRiseFall *&tr,
|
||||
|
|
@ -259,7 +293,8 @@ CheckSlewLimits::checkSlew(Vertex *vertex,
|
|||
}
|
||||
|
||||
PinSeq *
|
||||
CheckSlewLimits::pinSlewLimitViolations(const MinMax *min_max)
|
||||
CheckSlewLimits::pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
|
|
@ -267,17 +302,18 @@ CheckSlewLimits::pinSlewLimitViolations(const MinMax *min_max)
|
|||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinSlewLimitViolations(inst, min_max, violators);
|
||||
pinSlewLimitViolations(inst, corner, min_max, violators);
|
||||
}
|
||||
delete inst_iter;
|
||||
// Check top level ports.
|
||||
pinSlewLimitViolations(network->topInstance(), min_max, violators);
|
||||
sort(violators, PinSlewLimitSlackLess(min_max, this, sta_));
|
||||
pinSlewLimitViolations(network->topInstance(), corner, min_max, violators);
|
||||
sort(violators, PinSlewLimitSlackLess(corner, min_max, this, sta_));
|
||||
return violators;
|
||||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::pinSlewLimitViolations(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators)
|
||||
{
|
||||
|
|
@ -285,11 +321,11 @@ CheckSlewLimits::pinSlewLimitViolations(Instance *inst,
|
|||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
const Corner *corner;
|
||||
const Corner *corner1;
|
||||
const TransRiseFall *tr;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
checkSlews(pin, min_max, corner, tr, slew, limit, slack);
|
||||
checkSlews(pin, corner, min_max, corner1, tr, slew, limit, slack );
|
||||
if (tr && slack < 0.0)
|
||||
violators->push_back(pin);
|
||||
}
|
||||
|
|
@ -297,7 +333,8 @@ CheckSlewLimits::pinSlewLimitViolations(Instance *inst,
|
|||
}
|
||||
|
||||
Pin *
|
||||
CheckSlewLimits::pinMinSlewLimitSlack(const MinMax *min_max)
|
||||
CheckSlewLimits::pinMinSlewLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
|
|
@ -306,17 +343,18 @@ CheckSlewLimits::pinMinSlewLimitSlack(const MinMax *min_max)
|
|||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinMinSlewLimitSlack(inst, min_max, min_slack_pin, min_slack);
|
||||
pinMinSlewLimitSlack(inst, corner, min_max, min_slack_pin, min_slack);
|
||||
}
|
||||
delete inst_iter;
|
||||
// Check top level ports.
|
||||
pinMinSlewLimitSlack(network->topInstance(), min_max,
|
||||
pinMinSlewLimitSlack(network->topInstance(), corner, min_max,
|
||||
min_slack_pin, min_slack);
|
||||
return min_slack_pin;
|
||||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::pinMinSlewLimitSlack(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
|
|
@ -326,11 +364,11 @@ CheckSlewLimits::pinMinSlewLimitSlack(Instance *inst,
|
|||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
const Corner *corner;
|
||||
const Corner *corner1;
|
||||
const TransRiseFall *tr;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
checkSlews(pin, min_max, corner, tr, slew, limit, slack);
|
||||
checkSlews(pin, corner, min_max, corner1, tr, slew, limit, slack);
|
||||
if (tr
|
||||
&& (min_slack_pin == 0
|
||||
|| slack < min_slack)) {
|
||||
|
|
|
|||
|
|
@ -34,24 +34,48 @@ public:
|
|||
CheckSlewLimits(const StaState *sta);
|
||||
void init(const MinMax *min_max);
|
||||
// Requires init().
|
||||
// corner=NULL checks all corners.
|
||||
void checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
// Corner is NULL for no slew limit.
|
||||
const Corner *&corner,
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
PinSeq *pinSlewLimitViolations(const MinMax *min_max);
|
||||
Pin *pinMinSlewLimitSlack(const MinMax *min_max);
|
||||
// corner=NULL checks all corners.
|
||||
PinSeq *pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
// corner=NULL checks all corners.
|
||||
Pin *pinMinSlewLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
|
||||
protected:
|
||||
void checkSlews1(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
void checkSlews1(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
void checkSlew(Vertex *vertex,
|
||||
float limit1,
|
||||
const TransRiseFall *tr1,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
const TransRiseFall *tr1,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const TransRiseFall *&tr,
|
||||
|
|
@ -66,9 +90,11 @@ protected:
|
|||
float &limit1,
|
||||
bool &limit1_exists) const;
|
||||
void pinSlewLimitViolations(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators);
|
||||
void pinMinSlewLimitSlack(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
|
|
|
|||
|
|
@ -119,11 +119,12 @@ ClkSkews::ClkSkews(StaState *sta) :
|
|||
|
||||
void
|
||||
ClkSkews::reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits)
|
||||
{
|
||||
ClkSkewMap skews;
|
||||
findClkSkew(clks, setup_hold, skews);
|
||||
findClkSkew(clks, corner, setup_hold, skews);
|
||||
|
||||
// Sort the clocks to report in a stable order.
|
||||
ClockSeq sorted_clks;
|
||||
|
|
@ -167,6 +168,7 @@ ClkSkews::reportClkSkew(ClockSet *clks,
|
|||
|
||||
void
|
||||
ClkSkews::findClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
|
|
@ -184,7 +186,7 @@ ClkSkews::findClkSkew(ClockSet *clks,
|
|||
? tr->asRiseFallBoth()
|
||||
: TransRiseFallBoth::riseFall();
|
||||
findClkSkewFrom(src_vertex, q_vertex, src_tr, clks,
|
||||
setup_hold, skews);
|
||||
corner, setup_hold, skews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -210,6 +212,7 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
|
|||
Vertex *q_vertex,
|
||||
TransRiseFallBoth *src_tr,
|
||||
ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
|
|
@ -233,7 +236,7 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
|
|||
? tgt_tr1->asRiseFallBoth()
|
||||
: TransRiseFallBoth::riseFall();
|
||||
findClkSkew(src_vertex, src_tr, tgt_vertex, tgt_tr,
|
||||
clks, setup_hold, skews);
|
||||
clks, corner, setup_hold, skews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -245,6 +248,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
|||
Vertex *tgt_vertex,
|
||||
TransRiseFallBoth *tgt_tr,
|
||||
ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews)
|
||||
{
|
||||
|
|
@ -257,32 +261,35 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
|||
if (src_tr->matches(src_path->transition(this))
|
||||
&& src_path->minMax(this) == setup_hold
|
||||
&& clks->hasKey(src_clk)) {
|
||||
Corner *corner = src_path->pathAnalysisPt(this)->corner();
|
||||
VertexPathIterator tgt_iter(tgt_vertex, this);
|
||||
while (tgt_iter.hasNext()) {
|
||||
PathVertex *tgt_path = tgt_iter.next();
|
||||
Clock *tgt_clk = tgt_path->clock(this);
|
||||
if (tgt_clk == src_clk
|
||||
&& tgt_tr->matches(tgt_path->transition(this))
|
||||
&& tgt_path->minMax(this) == tgt_min_max
|
||||
&& tgt_path->pathAnalysisPt(this)->corner() == corner) {
|
||||
ClkSkew probe(src_path, tgt_path, this);
|
||||
ClkSkew *clk_skew = skews.findKey(src_clk);
|
||||
debugPrint8(debug_, "clk_skew", 2, "%s %s %s -> %s %s %s crpr = %s skew = %s\n",
|
||||
network_->pathName(src_path->pin(this)),
|
||||
src_path->transition(this)->asString(),
|
||||
time_unit->asString(probe.srcLatency(this)),
|
||||
network_->pathName(tgt_path->pin(this)),
|
||||
tgt_path->transition(this)->asString(),
|
||||
time_unit->asString(probe.tgtLatency(this)),
|
||||
time_unit->asString(probe.crpr(this)),
|
||||
time_unit->asString(probe.skew()));
|
||||
if (clk_skew == NULL) {
|
||||
clk_skew = new ClkSkew(probe);
|
||||
skews[src_clk] = clk_skew;
|
||||
Corner *src_corner = src_path->pathAnalysisPt(this)->corner();
|
||||
if (corner == NULL
|
||||
|| src_corner == corner) {
|
||||
VertexPathIterator tgt_iter(tgt_vertex, this);
|
||||
while (tgt_iter.hasNext()) {
|
||||
PathVertex *tgt_path = tgt_iter.next();
|
||||
Clock *tgt_clk = tgt_path->clock(this);
|
||||
if (tgt_clk == src_clk
|
||||
&& tgt_tr->matches(tgt_path->transition(this))
|
||||
&& tgt_path->minMax(this) == tgt_min_max
|
||||
&& tgt_path->pathAnalysisPt(this)->corner() == src_corner) {
|
||||
ClkSkew probe(src_path, tgt_path, this);
|
||||
ClkSkew *clk_skew = skews.findKey(src_clk);
|
||||
debugPrint8(debug_, "clk_skew", 2, "%s %s %s -> %s %s %s crpr = %s skew = %s\n",
|
||||
network_->pathName(src_path->pin(this)),
|
||||
src_path->transition(this)->asString(),
|
||||
time_unit->asString(probe.srcLatency(this)),
|
||||
network_->pathName(tgt_path->pin(this)),
|
||||
tgt_path->transition(this)->asString(),
|
||||
time_unit->asString(probe.tgtLatency(this)),
|
||||
time_unit->asString(probe.crpr(this)),
|
||||
time_unit->asString(probe.skew()));
|
||||
if (clk_skew == NULL) {
|
||||
clk_skew = new ClkSkew(probe);
|
||||
skews[src_clk] = clk_skew;
|
||||
}
|
||||
else if (fuzzyGreater(probe.skew(), clk_skew->skew()))
|
||||
clk_skew->copy(probe);
|
||||
}
|
||||
else if (fuzzyGreater(probe.skew(), clk_skew->skew()))
|
||||
clk_skew->copy(probe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,13 @@ public:
|
|||
ClkSkews(StaState *sta);
|
||||
// Report clk skews for clks.
|
||||
void reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
|
||||
protected:
|
||||
void findClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews);
|
||||
bool hasClkPaths(Vertex *vertex,
|
||||
|
|
@ -46,6 +48,7 @@ protected:
|
|||
Vertex *q_vertex,
|
||||
TransRiseFallBoth *src_tr,
|
||||
ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews);
|
||||
void findClkSkew(Vertex *src_vertex,
|
||||
|
|
@ -53,6 +56,7 @@ protected:
|
|||
Vertex *tgt_vertex,
|
||||
TransRiseFallBoth *tgt_tr,
|
||||
ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
ClkSkewMap &skews);
|
||||
void findFanout(Vertex *from,
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ ReportField::ReportField(const char *name,
|
|||
title_(stringCopy(title)),
|
||||
left_justify_(left_justify),
|
||||
unit_(unit),
|
||||
blank_(NULL),
|
||||
enabled_(enabled)
|
||||
enabled_(enabled),
|
||||
blank_(NULL)
|
||||
{
|
||||
setWidth(width);
|
||||
}
|
||||
|
|
@ -1872,7 +1872,7 @@ ReportPath::reportStartEndPoint(const char *pt,
|
|||
result += pt;
|
||||
reportEndOfLine(result);
|
||||
|
||||
for (int i = 0; i < strlen(key); i++)
|
||||
for (unsigned i = 0; i < strlen(key); i++)
|
||||
result += ' ';
|
||||
|
||||
result += " (";
|
||||
|
|
@ -2785,7 +2785,7 @@ ReportPath::nextArcAnnotated(const PathRef *next_path,
|
|||
{
|
||||
TimingArc *arc = expanded.prevArc(next_index);
|
||||
Edge *edge = next_path->prevEdge(arc, this);
|
||||
return edge->arcDelayAnnotated(arc, ap_index);
|
||||
return graph_->arcDelayAnnotated(edge, arc, ap_index);
|
||||
}
|
||||
|
||||
char *
|
||||
|
|
|
|||
130
search/Sta.cc
130
search/Sta.cc
|
|
@ -2384,8 +2384,9 @@ Sta::findPathEnds(ExceptionFrom *from,
|
|||
{
|
||||
searchPreamble();
|
||||
return search_->findPathEnds(from, thrus, to,
|
||||
corner, min_max, group_count, endpoint_count, unique_pins,
|
||||
slack_min, slack_max, sort_by_slack, group_names,
|
||||
corner, min_max, group_count, endpoint_count,
|
||||
unique_pins, slack_min, slack_max,
|
||||
sort_by_slack, group_names,
|
||||
setup, hold,
|
||||
recovery, removal,
|
||||
clk_gating_setup, clk_gating_hold);
|
||||
|
|
@ -2462,53 +2463,6 @@ Sta::reportPath(Path *path)
|
|||
report_path_->reportPath(path);
|
||||
}
|
||||
|
||||
PathEndSeq *
|
||||
Sta::reportCheckTypes(bool all_violators,
|
||||
bool setup,
|
||||
bool hold,
|
||||
bool recovery,
|
||||
bool removal,
|
||||
bool clock_gating_setup,
|
||||
bool clock_gating_hold)
|
||||
{
|
||||
MinMaxAll *path_min_max = MinMaxAll::max();
|
||||
if ((setup && hold)
|
||||
|| (recovery && removal)
|
||||
|| (clock_gating_setup && clock_gating_hold))
|
||||
path_min_max = MinMaxAll::all();
|
||||
else if (setup
|
||||
|| recovery
|
||||
|| clock_gating_setup)
|
||||
path_min_max = MinMaxAll::max();
|
||||
else if (hold
|
||||
|| removal
|
||||
|| clock_gating_hold)
|
||||
path_min_max = MinMaxAll::min();
|
||||
int group_count;
|
||||
float slack_min, slack_max;
|
||||
if (all_violators) {
|
||||
group_count = std::numeric_limits<int>::max();
|
||||
slack_min = -INF;
|
||||
slack_max = 0.0;
|
||||
}
|
||||
else {
|
||||
group_count = 1;
|
||||
slack_min = -INF;
|
||||
slack_max = INF;
|
||||
}
|
||||
return findPathEnds(NULL, NULL, NULL, // from, thru, to
|
||||
NULL, // corner
|
||||
path_min_max, group_count,
|
||||
1, // endpoint_count
|
||||
false, // unique_pins
|
||||
slack_min, slack_max,
|
||||
false, // sort_by_slack
|
||||
NULL, // group_names
|
||||
setup, hold,
|
||||
recovery, removal,
|
||||
clock_gating_setup, clock_gating_hold);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::updateTiming(bool full)
|
||||
{
|
||||
|
|
@ -2520,13 +2474,14 @@ Sta::updateTiming(bool full)
|
|||
|
||||
void
|
||||
Sta::reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits)
|
||||
{
|
||||
ensureClkArrivals();
|
||||
if (clk_skews_ == NULL)
|
||||
clk_skews_ = new ClkSkews(this);
|
||||
clk_skews_->reportClkSkew(clks, setup_hold, digits);
|
||||
clk_skews_->reportClkSkew(clks, corner, setup_hold, digits);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2966,16 +2921,16 @@ Sta::arcDelayAnnotated(Edge *edge,
|
|||
TimingArc *arc,
|
||||
DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
return edge->arcDelayAnnotated(arc, dcalc_ap->index());
|
||||
return graph_->arcDelayAnnotated(edge, arc, dcalc_ap->index());
|
||||
}
|
||||
|
||||
void
|
||||
Sta::setArcDelayAnnotated(bool annotated,
|
||||
Edge *edge,
|
||||
Sta::setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAnalysisPt *dcalc_ap)
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
bool annotated)
|
||||
{
|
||||
edge->setArcDelayAnnotated(annotated, arc, dcalc_ap->index());
|
||||
graph_->setArcDelayAnnotated(edge, arc, dcalc_ap->index(), annotated);
|
||||
Vertex *to = edge->to(graph_);
|
||||
search_->arrivalInvalid(to);
|
||||
search_->requiredInvalid(edge->from(graph_));
|
||||
|
|
@ -3159,7 +3114,7 @@ Sta::setArcDelay(Edge *edge,
|
|||
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||
graph_->setArcDelay(edge, arc, ap_index, delay);
|
||||
// Don't let delay calculation clobber the value.
|
||||
edge->setArcDelayAnnotated(true, arc, ap_index);
|
||||
graph_->setArcDelayAnnotated(edge, arc, ap_index, true);
|
||||
}
|
||||
if (edge->role()->isTimingCheck())
|
||||
search_->requiredInvalid(edge->to(graph_));
|
||||
|
|
@ -3326,10 +3281,10 @@ Sta::setPortExtFanout(Port *port,
|
|||
void
|
||||
Sta::setNetWireCap(Net *net,
|
||||
bool subtract_pin_cap,
|
||||
const Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
float cap)
|
||||
{
|
||||
Corner *corner = corners_->defaultCorner();
|
||||
MinMaxIterator mm_iter(min_max);
|
||||
while (mm_iter.hasNext()) {
|
||||
MinMax *mm = mm_iter.next();
|
||||
|
|
@ -3341,6 +3296,7 @@ Sta::setNetWireCap(Net *net,
|
|||
void
|
||||
Sta::connectedCap(Pin *drvr_pin,
|
||||
const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
float &pin_cap,
|
||||
float &wire_cap) const
|
||||
|
|
@ -3348,7 +3304,6 @@ Sta::connectedCap(Pin *drvr_pin,
|
|||
pin_cap = 0.0;
|
||||
wire_cap = 0.0;
|
||||
bool cap_exists = false;
|
||||
Corner *corner = corners_->defaultCorner();
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
||||
Parasitic *parasitic;
|
||||
bool delete_parasitic;
|
||||
|
|
@ -3371,13 +3326,14 @@ Sta::connectedCap(Pin *drvr_pin,
|
|||
void
|
||||
Sta::connectedCap(Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
float &pin_cap,
|
||||
float &wire_cap) const
|
||||
{
|
||||
Pin *drvr_pin = findNetParasiticDrvrPin(net);
|
||||
if (drvr_pin)
|
||||
connectedCap(drvr_pin, tr, min_max, pin_cap, wire_cap);
|
||||
connectedCap(drvr_pin, tr, corner, min_max, pin_cap, wire_cap);
|
||||
else {
|
||||
pin_cap = 0.0;
|
||||
wire_cap = 0.0;
|
||||
|
|
@ -4707,17 +4663,19 @@ Sta::checkSlewLimitPreamble()
|
|||
}
|
||||
|
||||
Pin *
|
||||
Sta::pinMinSlewLimitSlack(const MinMax *min_max)
|
||||
Sta::pinMinSlewLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
checkSlewLimitPreamble();
|
||||
return check_slew_limits_->pinMinSlewLimitSlack(min_max);
|
||||
return check_slew_limits_->pinMinSlewLimitSlack(corner, min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
Sta::pinSlewLimitViolations(const MinMax *min_max)
|
||||
Sta::pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
checkSlewLimitPreamble();
|
||||
return check_slew_limits_->pinSlewLimitViolations(min_max);
|
||||
return check_slew_limits_->pinSlewLimitViolations(corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4728,34 +4686,39 @@ Sta::reportSlewLimitShortHeader()
|
|||
|
||||
void
|
||||
Sta::reportSlewLimitShort(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Corner *corner;
|
||||
const Corner *corner1;
|
||||
const TransRiseFall *tr;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
check_slew_limits_->checkSlews(pin, min_max, corner, tr, slew, limit, slack);
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
report_path_->reportSlewLimitShort(pin, tr, slew, limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Corner *corner;
|
||||
const Corner *corner1;
|
||||
const TransRiseFall *tr;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
check_slew_limits_->checkSlews(pin, min_max, corner, tr, slew, limit, slack);
|
||||
report_path_->reportSlewLimitVerbose(pin, corner, tr, slew,
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner, tr, slew, limit, slack);
|
||||
report_path_->reportSlewLimitVerbose(pin, corner1, tr, slew,
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
|
|
@ -4763,8 +4726,8 @@ Sta::checkSlews(const Pin *pin,
|
|||
{
|
||||
checkSlewLimitPreamble();
|
||||
check_slew_limits_->init(min_max);
|
||||
check_slew_limits_->checkSlews(pin, min_max,
|
||||
corner, tr, slew, limit, slack);
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, tr, slew, limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
|
@ -4778,31 +4741,32 @@ Sta::minPulseWidthPreamble()
|
|||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
Sta::minPulseWidthChecks(PinSeq *pins)
|
||||
Sta::minPulseWidthChecks(PinSeq *pins,
|
||||
const Corner *corner)
|
||||
{
|
||||
minPulseWidthPreamble();
|
||||
return check_min_pulse_widths_->check(pins);
|
||||
return check_min_pulse_widths_->check(pins, corner);
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
Sta::minPulseWidthChecks()
|
||||
Sta::minPulseWidthChecks(const Corner *corner)
|
||||
{
|
||||
minPulseWidthPreamble();
|
||||
return check_min_pulse_widths_->check();
|
||||
return check_min_pulse_widths_->check(corner);
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
Sta::minPulseWidthViolations()
|
||||
Sta::minPulseWidthViolations(const Corner *corner)
|
||||
{
|
||||
minPulseWidthPreamble();
|
||||
return check_min_pulse_widths_->violations();
|
||||
return check_min_pulse_widths_->violations(corner);
|
||||
}
|
||||
|
||||
MinPulseWidthCheck *
|
||||
Sta::minPulseWidthSlack()
|
||||
Sta::minPulseWidthSlack(const Corner *corner)
|
||||
{
|
||||
minPulseWidthPreamble();
|
||||
return check_min_pulse_widths_->minSlackCheck();
|
||||
return check_min_pulse_widths_->minSlackCheck(corner);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4822,17 +4786,17 @@ Sta::reportMpwCheck(MinPulseWidthCheck *check,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
MinPeriodCheckSeq &
|
||||
Sta::minPeriodViolations()
|
||||
Sta::minPeriodViolations(const Corner *corner)
|
||||
{
|
||||
minPeriodPreamble();
|
||||
return check_min_periods_->violations();
|
||||
return check_min_periods_->violations(corner);
|
||||
}
|
||||
|
||||
MinPeriodCheck *
|
||||
Sta::minPeriodSlack()
|
||||
Sta::minPeriodSlack(const Corner *corner)
|
||||
{
|
||||
minPeriodPreamble();
|
||||
return check_min_periods_->minSlackCheck();
|
||||
return check_min_periods_->minSlackCheck(corner);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ public:
|
|||
// Set net wire capacitance (set_load -wire net).
|
||||
void setNetWireCap(Net *net,
|
||||
bool subtract_pin_load,
|
||||
const Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
float cap);
|
||||
// Port external fanout (used by wireload models).
|
||||
|
|
@ -188,11 +189,13 @@ public:
|
|||
// wire_cap = annotated net capacitance + port external wire capacitance.
|
||||
void connectedCap(Pin *drvr_pin,
|
||||
const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
void connectedCap(Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
|
|
@ -605,39 +608,53 @@ public:
|
|||
ClockSet &clks);
|
||||
|
||||
// Return the pin with the min/max slew limit slack.
|
||||
Pin *pinMinSlewLimitSlack(const MinMax *min_max);
|
||||
// corner=NULL checks all corners.
|
||||
Pin *pinMinSlewLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
// Return all pins with min/max slew violations.
|
||||
PinSeq *pinSlewLimitViolations(const MinMax *min_max);
|
||||
// corner=NULL checks all corners.
|
||||
PinSeq *pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void reportSlewLimitShortHeader();
|
||||
void reportSlewLimitShort(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const Corner *&corner1,
|
||||
const TransRiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack);
|
||||
// Min pulse width check with the least slack.
|
||||
MinPulseWidthCheck *minPulseWidthSlack();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheck *minPulseWidthSlack(const Corner *corner);
|
||||
// All violating min pulse width checks.
|
||||
MinPulseWidthCheckSeq &minPulseWidthViolations();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &minPulseWidthViolations(const Corner *corner);
|
||||
// Min pulse width checks for pins.
|
||||
MinPulseWidthCheckSeq &minPulseWidthChecks(PinSeq *pins);
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &minPulseWidthChecks(PinSeq *pins,
|
||||
const Corner *corner);
|
||||
// All min pulse width checks.
|
||||
MinPulseWidthCheckSeq &minPulseWidthChecks();
|
||||
// corner=NULL checks all corners.
|
||||
MinPulseWidthCheckSeq &minPulseWidthChecks(const Corner *corner);
|
||||
void reportMpwChecks(MinPulseWidthCheckSeq *checks,
|
||||
bool verbose);
|
||||
void reportMpwCheck(MinPulseWidthCheck *check,
|
||||
bool verbose);
|
||||
|
||||
// Min period check with the least slack.
|
||||
MinPeriodCheck *minPeriodSlack();
|
||||
// corner=NULL checks all corners.
|
||||
MinPeriodCheck *minPeriodSlack(const Corner *corner);
|
||||
// All violating min period checks.
|
||||
MinPeriodCheckSeq &minPeriodViolations();
|
||||
// corner=NULL checks all corners.
|
||||
MinPeriodCheckSeq &minPeriodViolations(const Corner *corner);
|
||||
void reportChecks(MinPeriodCheckSeq *checks,
|
||||
bool verbose);
|
||||
void reportCheck(MinPeriodCheck *check,
|
||||
|
|
@ -836,13 +853,6 @@ public:
|
|||
bool removal,
|
||||
bool clk_gating_setup,
|
||||
bool clk_gating_hold) __attribute__ ((deprecated));
|
||||
PathEndSeq *reportCheckTypes(bool all_violators,
|
||||
bool setup,
|
||||
bool hold,
|
||||
bool recovery,
|
||||
bool removal,
|
||||
bool clock_gating_setup,
|
||||
bool clock_gating_hold);
|
||||
void setReportPathFormat(ReportPathFormat format);
|
||||
void setReportPathFieldOrder(StringSeq *field_names);
|
||||
void setReportPathFields(bool report_input_pin,
|
||||
|
|
@ -854,6 +864,7 @@ public:
|
|||
void setReportPathNoSplit(bool no_split);
|
||||
// Report clk skews for clks.
|
||||
void reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
void reportPathEnds(PathEndSeq *ends);
|
||||
|
|
@ -977,10 +988,10 @@ public:
|
|||
TimingArc *arc,
|
||||
DcalcAnalysisPt *dcalc_ap);
|
||||
// Set/unset the back-annotation flag for a timing arc.
|
||||
void setArcDelayAnnotated(bool annotated,
|
||||
Edge *edge,
|
||||
void setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
DcalcAnalysisPt *dcalc_ap);
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
bool annotated);
|
||||
// Make sure levels are up to date and return vertex level.
|
||||
Level vertexLevel(Vertex *vertex);
|
||||
GraphLoopSeq *graphLoops();
|
||||
|
|
|
|||
|
|
@ -324,9 +324,10 @@ proc net_connected_pins_sorted { net } {
|
|||
}
|
||||
|
||||
proc report_net_caps { net pins digits } {
|
||||
report_net_cap $net "Pin" "pin_capacitance" $digits
|
||||
report_net_cap $net "Wire" "wire_capacitance" $digits
|
||||
report_net_cap $net "Total" "capacitance" $digits
|
||||
set corner [default_corner]
|
||||
report_net_cap $net "Pin" "pin_capacitance" $corner $digits
|
||||
report_net_cap $net "Wire" "wire_capacitance" $corner $digits
|
||||
report_net_cap $net "Total" "capacitance" $corner $digits
|
||||
|
||||
set pin_count 0
|
||||
set driver_count 0
|
||||
|
|
@ -347,11 +348,11 @@ proc report_net_caps { net pins digits } {
|
|||
puts ""
|
||||
}
|
||||
|
||||
proc report_net_cap { net caption cap_msg digits } {
|
||||
set cap_r_min [$net $cap_msg "rise" "min"]
|
||||
set cap_r_max [$net $cap_msg "rise" "max"]
|
||||
set cap_f_min [$net $cap_msg "fall" "min"]
|
||||
set cap_f_max [$net $cap_msg "fall" "max"]
|
||||
proc report_net_cap { net caption cap_msg corner digits } {
|
||||
set cap_r_min [$net $cap_msg "rise" $corner "min"]
|
||||
set cap_r_max [$net $cap_msg "rise" $corner "max"]
|
||||
set cap_f_min [$net $cap_msg "fall" $corner "min"]
|
||||
set cap_f_max [$net $cap_msg "fall" $corner "max"]
|
||||
puts " $caption capacitance: [capacitances_str $cap_r_min $cap_r_max $cap_f_min $cap_f_max $digits]"
|
||||
}
|
||||
|
||||
|
|
|
|||
10
tcl/Sdc.tcl
10
tcl/Sdc.tcl
|
|
@ -2356,18 +2356,20 @@ proc set_input_transition { args } {
|
|||
################################################################
|
||||
|
||||
define_cmd_args "set_load" \
|
||||
{[-rise] [-fall] [-max] [-min] [-subtract_pin_load] [-pin_load] [-wire_load]\
|
||||
capacitance objects}
|
||||
{[-rise] [-fall] [-max] [-min] [-corner corner] [-subtract_pin_load]\
|
||||
[-pin_load] [-wire_load] capacitance objects}
|
||||
|
||||
proc set_load { args } {
|
||||
parse_key_args "set_load" args keys {} \
|
||||
flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}
|
||||
flags {-rise -fall -min -max -corner -subtract_pin_load \
|
||||
-pin_load -wire_load}
|
||||
|
||||
check_argc_eq2 "set_load" $args
|
||||
|
||||
set pin_load [info exists flags(-pin_load)]
|
||||
set wire_load [info exists flags(-wire_load)]
|
||||
set subtract_pin_load [info exists flags(-subtract_pin_load)]
|
||||
set corner [parse_corner keys]
|
||||
set min_max [parse_min_max_all_check_flags flags]
|
||||
set tr [parse_rise_fall_flags flags]
|
||||
|
||||
|
|
@ -2399,7 +2401,7 @@ proc set_load { args } {
|
|||
sta_warn "-rise/-fall not allowed for net objects."
|
||||
}
|
||||
foreach net $nets {
|
||||
set_net_wire_cap $net $subtract_pin_load $min_max $cap
|
||||
set_net_wire_cap $net $subtract_pin_load $corner $min_max $cap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,36 +288,36 @@ proc parse_path_group_arg { group_names } {
|
|||
return $names
|
||||
}
|
||||
|
||||
proc report_slew_limits { min_max all_violators verbose nosplit } {
|
||||
proc report_slew_limits { corner min_max all_violators verbose nosplit } {
|
||||
if { $all_violators } {
|
||||
set violators [pin_slew_limit_violations $min_max]
|
||||
set violators [pin_slew_limit_violations $corner $min_max]
|
||||
if { $violators != {} } {
|
||||
puts "${min_max}_transition"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
foreach pin $violators {
|
||||
report_slew_limit_verbose $pin $min_max
|
||||
report_slew_limit_verbose $pin $corner $min_max
|
||||
puts ""
|
||||
}
|
||||
} else {
|
||||
report_slew_limit_short_header
|
||||
foreach pin $violators {
|
||||
report_slew_limit_short $pin $min_max
|
||||
report_slew_limit_short $pin $corner $min_max
|
||||
}
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set pin [pin_min_slew_limit_slack $min_max]
|
||||
set pin [pin_min_slew_limit_slack $corner $min_max]
|
||||
if { $pin != "NULL" } {
|
||||
puts "${min_max}_transition"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
report_slew_limit_verbose $pin $min_max
|
||||
report_slew_limit_verbose $pin $corner $min_max
|
||||
puts ""
|
||||
} else {
|
||||
report_slew_limit_short_header
|
||||
report_slew_limit_short $pin $min_max
|
||||
report_slew_limit_short $pin $corner $min_max
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
77
tcl/Sta.tcl
77
tcl/Sta.tcl
|
|
@ -99,15 +99,16 @@ proc find_timing { args } {
|
|||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_clock_skew" {[-setup|-hold] \
|
||||
[-clock clocks] \
|
||||
define_sta_cmd_args "report_clock_skew" {[-setup|-hold]\
|
||||
[-clock clocks]\
|
||||
[-corner corner_name]]\
|
||||
[-digits digits]}
|
||||
|
||||
proc_redirect report_clock_skew {
|
||||
global sta_report_default_digits
|
||||
|
||||
parse_key_args "report_clock_skew" args \
|
||||
keys {-clock -digits} flags {-setup -hold}
|
||||
keys {-clock -corner -digits} flags {-setup -hold}
|
||||
check_argc_eq0 "report_clock_skew" $args
|
||||
|
||||
if { [info exists flags(-setup)] && [info exists flags(-hold)] } {
|
||||
|
|
@ -125,13 +126,14 @@ proc_redirect report_clock_skew {
|
|||
} else {
|
||||
set clks [all_clocks]
|
||||
}
|
||||
set corner [parse_corner_or_all keys]
|
||||
if [info exists keys(-digits)] {
|
||||
set digits $keys(-digits)
|
||||
check_positive_integer "-digits" $digits
|
||||
} else {
|
||||
set digits $sta_report_default_digits
|
||||
}
|
||||
report_clk_skew $clks $setup_hold $digits
|
||||
report_clk_skew $clks $corner $setup_hold $digits
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
@ -141,10 +143,10 @@ define_sta_cmd_args "report_checks" \
|
|||
[-through through_list|-rise_through through_list|-fall_through through_list]\
|
||||
[-to to_list|-rise_to to_list|-fall_to to_list]\
|
||||
[-path_delay min|min_rise|min_fall|max|max_rise|max_fall|min_max]\
|
||||
[-corner corner_name]\
|
||||
[-group_count path_count] \
|
||||
[-endpoint_count path_count]\
|
||||
[-unique_paths_to_endpoint]\
|
||||
[-corner corner_name]\
|
||||
[-slack_max slack_max]\
|
||||
[-slack_min slack_min]\
|
||||
[-sort_by_slack]\
|
||||
|
|
@ -161,7 +163,7 @@ proc_redirect report_checks {
|
|||
|
||||
parse_key_args "report_checks" args \
|
||||
keys {-from -rise_from -fall_from -to -rise_to -fall_to \
|
||||
-path_delay -group_count -endpoint_count -corner \
|
||||
-path_delay -corner -group_count -endpoint_count \
|
||||
-slack_max -slack_min -path_group} \
|
||||
flags {-sort_by_slack -unique_paths_to_endpoint} 0
|
||||
|
||||
|
|
@ -203,6 +205,8 @@ proc_redirect report_checks {
|
|||
|
||||
check_for_key_args $cmd args
|
||||
|
||||
set corner [parse_corner_or_all keys]
|
||||
|
||||
set endpoint_count 1
|
||||
if [info exists keys(-endpoint_count)] {
|
||||
set endpoint_count $keys(-endpoint_count)
|
||||
|
|
@ -221,8 +225,6 @@ proc_redirect report_checks {
|
|||
|
||||
set unique_pins [info exists flags(-unique_paths_to_endpoint)]
|
||||
|
||||
set corner [parse_corner_or_all keys]
|
||||
|
||||
set slack_min "-1e+30"
|
||||
if [info exist keys(-slack_min)] {
|
||||
set slack_min $keys(-slack_min)
|
||||
|
|
@ -254,10 +256,11 @@ proc_redirect report_checks {
|
|||
}
|
||||
}
|
||||
|
||||
set path_ends [find_path_ends $from $thrus $to $min_max \
|
||||
$group_count $endpoint_count $unique_pins $corner \
|
||||
set path_ends [find_path_ends $from $thrus $to $corner $min_max \
|
||||
$group_count $endpoint_count $unique_pins \
|
||||
$slack_min $slack_max \
|
||||
$sort_by_slack $groups]
|
||||
$sort_by_slack $groups \
|
||||
1 1 1 1 1 1]
|
||||
if { [$path_ends empty] } {
|
||||
if { $sta_report_unconstrained_paths } {
|
||||
puts "No paths."
|
||||
|
|
@ -274,6 +277,7 @@ proc_redirect report_checks {
|
|||
|
||||
define_sta_cmd_args "report_check_types" \
|
||||
{[-all_violators] [-verbose]\
|
||||
[-corner corner_name]\
|
||||
[-format slack_only|end]\
|
||||
[-max_delay] [-min_delay]\
|
||||
[-recovery] [-removal]\
|
||||
|
|
@ -286,7 +290,7 @@ define_sta_cmd_args "report_check_types" \
|
|||
proc_redirect report_check_types {
|
||||
variable path_options
|
||||
|
||||
parse_key_args "report_check_types" args keys {}\
|
||||
parse_key_args "report_check_types" args keys {-corner}\
|
||||
flags {-all_violators -verbose -no_line_splits} 0
|
||||
|
||||
set all_violators [info exists flags(-all_violators)]
|
||||
|
|
@ -305,6 +309,8 @@ proc_redirect report_check_types {
|
|||
set min_max "max"
|
||||
}
|
||||
|
||||
set corner [parse_corner_or_all keys]
|
||||
|
||||
if { $args == {} } {
|
||||
if { $min_max == "max" || $min_max == "min_max" } {
|
||||
set setup 1
|
||||
|
|
@ -362,9 +368,32 @@ proc_redirect report_check_types {
|
|||
sta_error "positional arguments not supported."
|
||||
}
|
||||
|
||||
set corner [parse_corner_or_all keys]
|
||||
|
||||
if { $setup || $hold || $recovery || $removal \
|
||||
|| $clk_gating_setup || $clk_gating_hold } {
|
||||
set path_ends [report_check_types_cmd $all_violators \
|
||||
if { ($setup && $hold) \
|
||||
|| ($recovery && $removal) \
|
||||
|| ($clk_gating_setup && $clk_gating_hold) } {
|
||||
set path_min_max "min_max"
|
||||
} elseif { $setup || $recovery || $clk_gating_setup } {
|
||||
set path_min_max "max"
|
||||
} elseif { $hold || $removal || $clk_gating_hold } {
|
||||
set path_min_max "min"
|
||||
}
|
||||
if { $all_violators } {
|
||||
set group_count $sta::int_max
|
||||
set slack_min [expr -$sta::float_inf]
|
||||
set slack_max 0.0
|
||||
} else {
|
||||
set group_count 1
|
||||
set slack_min [expr -$sta::float_inf]
|
||||
set slack_max $sta::float_inf
|
||||
}
|
||||
set path_ends [find_path_ends "NULL" {} "NULL" \
|
||||
$corner $path_min_max $group_count 1 0 \
|
||||
$slack_min $slack_max \
|
||||
0 {} \
|
||||
$setup $hold \
|
||||
$recovery $removal \
|
||||
$clk_gating_setup $clk_gating_hold]
|
||||
|
|
@ -373,17 +402,17 @@ proc_redirect report_check_types {
|
|||
}
|
||||
|
||||
if { $max_transition } {
|
||||
report_slew_limits "max" $all_violators $verbose $nosplit
|
||||
report_slew_limits $corner "max" $all_violators $verbose $nosplit
|
||||
}
|
||||
if { $min_transition } {
|
||||
report_slew_limits "min" $all_violators $verbose $nosplit
|
||||
report_slew_limits $corner "min" $all_violators $verbose $nosplit
|
||||
}
|
||||
if { $min_pulse_width } {
|
||||
if { $all_violators } {
|
||||
set checks [min_pulse_width_violations]
|
||||
set checks [min_pulse_width_violations $corner]
|
||||
report_mpw_checks $checks $verbose
|
||||
} else {
|
||||
set check [min_pulse_width_check_slack]
|
||||
set check [min_pulse_width_check_slack $corner]
|
||||
if { $check != "NULL" } {
|
||||
report_mpw_check $check $verbose
|
||||
}
|
||||
|
|
@ -391,10 +420,10 @@ proc_redirect report_check_types {
|
|||
}
|
||||
if { $min_period } {
|
||||
if { $all_violators } {
|
||||
set checks [min_period_violations]
|
||||
set checks [min_period_violations $corner]
|
||||
report_min_period_checks $checks $verbose
|
||||
} else {
|
||||
set check [min_period_check_slack]
|
||||
set check [min_period_check_slack $corner]
|
||||
if { $check != "NULL" } {
|
||||
report_min_period_check $check $verbose
|
||||
}
|
||||
|
|
@ -429,22 +458,24 @@ define_sta_cmd_args "report_disabled_edges" {}
|
|||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_pulse_width_checks" \
|
||||
{[-verbose] [-digits digits] [-no_line_splits] [pins]\
|
||||
{[-verbose] [-corner corner_name] [-digits digits] [-no_line_splits] [pins]\
|
||||
[> filename] [>> filename]}
|
||||
|
||||
proc_redirect report_pulse_width_checks {
|
||||
variable path_options
|
||||
|
||||
parse_key_args "report_pulse_width_checks" args keys {} flags {-verbose} 0
|
||||
parse_key_args "report_pulse_width_checks" args keys {-corner} \
|
||||
flags {-verbose} 0
|
||||
# Only -digits and -no_line_splits are respected.
|
||||
parse_report_path_options "report_pulse_width_checks" args "full" 0
|
||||
check_argc_eq0or1 "report_pulse_width_checks" $args
|
||||
set corner [parse_corner_or_all keys]
|
||||
set verbose [info exists flags(-verbose)]
|
||||
if { [llength $args] == 1 } {
|
||||
set pins [get_port_pins_error "pins" [lindex $args 0]]
|
||||
set checks [min_pulse_width_check_pins $pins]
|
||||
set checks [min_pulse_width_check_pins $pins $corner]
|
||||
} else {
|
||||
set checks [min_pulse_width_checks]
|
||||
set checks [min_pulse_width_checks $corner]
|
||||
}
|
||||
if { $checks != {} } {
|
||||
report_mpw_checks $checks $verbose
|
||||
|
|
|
|||
107
tcl/StaTcl.i
107
tcl/StaTcl.i
|
|
@ -2318,6 +2318,9 @@ private:
|
|||
|
||||
%inline %{
|
||||
|
||||
float float_inf = INF;
|
||||
int int_max = std::numeric_limits<int>::max();
|
||||
|
||||
const char *
|
||||
version()
|
||||
{
|
||||
|
|
@ -3163,10 +3166,11 @@ set_port_ext_fanout_cmd(Port *port,
|
|||
void
|
||||
set_net_wire_cap(Net *net,
|
||||
bool subtract_pin_cap,
|
||||
Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
float cap)
|
||||
{
|
||||
Sta::sta()->setNetWireCap(net, subtract_pin_cap, min_max, cap);
|
||||
Sta::sta()->setNetWireCap(net, subtract_pin_cap, corner, min_max, cap);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4414,15 +4418,21 @@ PathEndSeq *
|
|||
find_path_ends(ExceptionFrom *from,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
Corner *corner,
|
||||
const MinMaxAll *delay_min_max,
|
||||
int group_count,
|
||||
int endpoint_count,
|
||||
bool unique_pins,
|
||||
Corner *corner,
|
||||
float slack_min,
|
||||
float slack_max,
|
||||
bool sort_by_slack,
|
||||
PathGroupNameSet *groups)
|
||||
PathGroupNameSet *groups,
|
||||
bool setup,
|
||||
bool hold,
|
||||
bool recovery,
|
||||
bool removal,
|
||||
bool clk_gating_setup,
|
||||
bool clk_gating_hold)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
Sta *sta = Sta::sta();
|
||||
|
|
@ -4430,30 +4440,15 @@ find_path_ends(ExceptionFrom *from,
|
|||
corner, delay_min_max,
|
||||
group_count, endpoint_count, unique_pins,
|
||||
slack_min, slack_max,
|
||||
sort_by_slack, groups,
|
||||
true, true, // setup, hold
|
||||
true, true, // recovery, removal
|
||||
true, true); // clk gating setup, hold
|
||||
sort_by_slack,
|
||||
groups->size() ? groups : NULL,
|
||||
setup, hold,
|
||||
recovery, removal,
|
||||
clk_gating_setup, clk_gating_hold);
|
||||
delete groups;
|
||||
return ends;
|
||||
}
|
||||
|
||||
PathEndSeq *
|
||||
report_check_types_cmd(bool all_violators,
|
||||
bool setup,
|
||||
bool hold,
|
||||
bool recovery,
|
||||
bool removal,
|
||||
bool clock_gating_setup,
|
||||
bool clock_gating_hold)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->reportCheckTypes(all_violators,
|
||||
setup, hold,
|
||||
recovery, removal,
|
||||
clock_gating_setup, clock_gating_hold);
|
||||
}
|
||||
|
||||
void
|
||||
set_report_path_format(ReportPathFormat format)
|
||||
{
|
||||
|
|
@ -4537,11 +4532,12 @@ report_path_cmd(Path *path)
|
|||
|
||||
void
|
||||
report_clk_skew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
Sta::sta()->reportClkSkew(clks, setup_hold, digits);
|
||||
Sta::sta()->reportClkSkew(clks, corner, setup_hold, digits);
|
||||
delete clks;
|
||||
}
|
||||
|
||||
|
|
@ -4577,33 +4573,35 @@ group_path_pins(const char *group_path_name)
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
min_pulse_width_violations()
|
||||
min_pulse_width_violations(const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->minPulseWidthViolations();
|
||||
return Sta::sta()->minPulseWidthViolations(corner);
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
min_pulse_width_check_pins(PinSeq *pins)
|
||||
min_pulse_width_check_pins(PinSeq *pins,
|
||||
const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
MinPulseWidthCheckSeq &checks = Sta::sta()->minPulseWidthChecks(pins);
|
||||
Sta *sta = Sta::sta();
|
||||
MinPulseWidthCheckSeq &checks = sta->minPulseWidthChecks(pins, corner);
|
||||
delete pins;
|
||||
return checks;
|
||||
}
|
||||
|
||||
MinPulseWidthCheckSeq &
|
||||
min_pulse_width_checks()
|
||||
min_pulse_width_checks(const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->minPulseWidthChecks();
|
||||
return Sta::sta()->minPulseWidthChecks(corner);
|
||||
}
|
||||
|
||||
MinPulseWidthCheck *
|
||||
min_pulse_width_check_slack()
|
||||
min_pulse_width_check_slack(const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->minPulseWidthSlack();
|
||||
return Sta::sta()->minPulseWidthSlack(corner);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4623,17 +4621,17 @@ report_mpw_check(MinPulseWidthCheck *check,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
MinPeriodCheckSeq &
|
||||
min_period_violations()
|
||||
min_period_violations(const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->minPeriodViolations();
|
||||
return Sta::sta()->minPeriodViolations(corner);
|
||||
}
|
||||
|
||||
MinPeriodCheck *
|
||||
min_period_check_slack()
|
||||
min_period_check_slack(const Corner *corner)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->minPeriodSlack();
|
||||
return Sta::sta()->minPeriodSlack(corner);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4779,17 +4777,19 @@ report_delay_calc_cmd(Edge *edge,
|
|||
}
|
||||
|
||||
Pin *
|
||||
pin_min_slew_limit_slack(const MinMax *min_max)
|
||||
pin_min_slew_limit_slack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinMinSlewLimitSlack(min_max);
|
||||
return Sta::sta()->pinMinSlewLimitSlack(corner, min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
pin_slew_limit_violations(const MinMax *min_max)
|
||||
pin_slew_limit_violations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinSlewLimitViolations(min_max);
|
||||
return Sta::sta()->pinSlewLimitViolations(corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4800,16 +4800,18 @@ report_slew_limit_short_header()
|
|||
|
||||
void
|
||||
report_slew_limit_short(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportSlewLimitShort(pin, min_max);
|
||||
Sta::sta()->reportSlewLimitShort(pin, corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
report_slew_limit_verbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportSlewLimitVerbose(pin, min_max);
|
||||
Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max);
|
||||
}
|
||||
|
||||
EdgeSeq *
|
||||
|
|
@ -4937,13 +4939,14 @@ unset_clock_groups_asynchronous(const char *name)
|
|||
Sta::sta()->removeClockGroupsAsynchronous(name);
|
||||
}
|
||||
|
||||
// Debugging function.
|
||||
bool
|
||||
same_clk_group(Clock *clk1,
|
||||
Clock *clk2)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
Sdc *sdc = sta->sdc();
|
||||
return sdc->sameClockGroup(clk1, clk2);
|
||||
return sdc->sameClockGroupExplicit(clk1, clk2);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -5725,31 +5728,34 @@ vertices()
|
|||
|
||||
float
|
||||
capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return pin_cap + wire_cap;
|
||||
}
|
||||
|
||||
float
|
||||
pin_capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return pin_cap;
|
||||
}
|
||||
|
||||
float
|
||||
wire_capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return wire_cap;
|
||||
}
|
||||
|
||||
|
|
@ -5786,31 +5792,34 @@ bool is_ground() { return cmdLinkedNetwork()->isGround(self);}
|
|||
|
||||
float
|
||||
capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return pin_cap + wire_cap;
|
||||
}
|
||||
|
||||
float
|
||||
pin_capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return pin_cap;
|
||||
}
|
||||
|
||||
float
|
||||
wire_capacitance(const TransRiseFall *tr,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
float pin_cap, wire_cap;
|
||||
Sta::sta()->connectedCap(self, tr, min_max, pin_cap, wire_cap);
|
||||
Sta::sta()->connectedCap(self, tr, corner, min_max, pin_cap, wire_cap);
|
||||
return wire_cap;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ verilogFlushBuffer()
|
|||
%option never-interactive
|
||||
|
||||
%x COMMENT
|
||||
%x ATTRIBUTE
|
||||
%x QSTRING
|
||||
|
||||
SIGN "+"|"-"
|
||||
|
|
@ -78,6 +79,21 @@ ID_TOKEN {ID_ESCAPED_TOKEN}|{ID_ALPHA_TOKEN}
|
|||
}
|
||||
}
|
||||
|
||||
"(*" { BEGIN ATTRIBUTE; }
|
||||
<ATTRIBUTE>{
|
||||
.
|
||||
|
||||
{EOL} { sta::verilog_reader->incrLine(); }
|
||||
|
||||
"*)" { BEGIN INITIAL; }
|
||||
|
||||
<<EOF>> {
|
||||
VerilogParse_error("unterminated attribute");
|
||||
BEGIN(INITIAL);
|
||||
yyterminate();
|
||||
}
|
||||
}
|
||||
|
||||
{SIGN}?{UNSIGNED_NUMBER}?"'"[bB][01_xz]+ {
|
||||
VerilogParse_lval.constant = sta::stringCopy(VerilogLex_text);
|
||||
return CONSTANT;
|
||||
|
|
|
|||
Loading…
Reference in New Issue