find_timing_paths
This commit is contained in:
parent
d29d66c7fb
commit
e1059eac12
2
README
2
README
|
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Parallax Gate Level Static Timing Analyzer
|
||||
See INSTALL for build instructions.
|
||||
See INSTALL for installation and build instructions.
|
||||
|
||||
Standard file formats
|
||||
Verilog
|
||||
|
|
|
|||
|
|
@ -135,6 +135,14 @@ LibertyLibrary::~LibertyLibrary()
|
|||
deleteEquivCellMap(equiv_cell_map_);
|
||||
delete units_;
|
||||
ocv_derate_map_.deleteContents();
|
||||
|
||||
SupplyVoltageMap::Iterator supply_iter(supply_voltage_map_);
|
||||
while (supply_iter.hasNext()) {
|
||||
const char *supply_name;
|
||||
float voltage;
|
||||
supply_iter.next(supply_name, voltage);
|
||||
stringDelete(supply_name);
|
||||
}
|
||||
}
|
||||
|
||||
LibertyCell *
|
||||
|
|
@ -762,6 +770,19 @@ LibertyLibrary::addOcvDerate(OcvDerate *derate)
|
|||
ocv_derate_map_[derate->name()] = derate;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::addSupplyVoltage(const char *supply_name,
|
||||
float voltage)
|
||||
{
|
||||
supply_voltage_map_[stringCopy(supply_name)] = voltage;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyLibrary::supplyVoltage(const char *supply_name)
|
||||
{
|
||||
return supply_voltage_map_[supply_name];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
LibertyCellIterator::LibertyCellIterator(const LibertyLibrary *
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ typedef Map<TimingArcSet*, LatchEnable*> LatchEnableMap;
|
|||
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
|
||||
typedef Vector<TimingArcAttrs*> TimingArcAttrsSeq;
|
||||
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
|
||||
typedef Map<const char *, float, CharPtrLess> SupplyVoltageMap;
|
||||
|
||||
typedef enum {
|
||||
clock_gate_none,
|
||||
|
|
@ -263,6 +264,9 @@ public:
|
|||
void setDefaultOcvDerate(OcvDerate *derate);
|
||||
OcvDerate *findOcvDerate(const char *derate_name);
|
||||
void addOcvDerate(OcvDerate *derate);
|
||||
void addSupplyVoltage(const char *suppy_name,
|
||||
float voltage);
|
||||
float supplyVoltage(const char *suppy_name);
|
||||
|
||||
// Make scaled cell. Call LibertyCell::addScaledCell after it is complete.
|
||||
LibertyCell *makeScaledCell(const char *name,
|
||||
|
|
@ -323,6 +327,7 @@ protected:
|
|||
float ocv_arc_depth_;
|
||||
OcvDerate *default_ocv_derate_;
|
||||
OcvDerateMap ocv_derate_map_;
|
||||
SupplyVoltageMap supply_voltage_map_;
|
||||
|
||||
// Set if any library has rise/fall capacitances.
|
||||
static bool found_rise_fall_caps_;
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ LibertyReader::defineVisitors()
|
|||
defineAttrVisitor("leakage_power_unit", &LibertyReader::visitPowerUnit);
|
||||
defineAttrVisitor("delay_model", &LibertyReader::visitDelayModel);
|
||||
defineAttrVisitor("bus_naming_style", &LibertyReader::visitBusStyle);
|
||||
defineAttrVisitor("voltage_map", &LibertyReader::visitVoltageMap);
|
||||
defineAttrVisitor("nom_temperature", &LibertyReader::visitNomTemp);
|
||||
defineAttrVisitor("nom_voltage", &LibertyReader::visitNomVolt);
|
||||
defineAttrVisitor("nom_process", &LibertyReader::visitNomProc);
|
||||
|
|
@ -832,6 +833,39 @@ LibertyReader::visitBusStyle(LibertyAttr *attr)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitVoltageMap(LibertyAttr *attr)
|
||||
{
|
||||
if (library_) {
|
||||
if (attr->isComplex()) {
|
||||
LibertyAttrValueIterator value_iter(attr->values());
|
||||
if (value_iter.hasNext()) {
|
||||
LibertyAttrValue *value = value_iter.next();
|
||||
if (value->isString()) {
|
||||
const char *supply_name = value->stringValue();
|
||||
if (value_iter.hasNext()) {
|
||||
value = value_iter.next();
|
||||
if (value->isFloat()) {
|
||||
float voltage = value->floatValue();
|
||||
library_->addSupplyVoltage(supply_name, voltage);
|
||||
}
|
||||
else
|
||||
libWarn(attr, "voltage_map voltage is not a float.\n");
|
||||
}
|
||||
else
|
||||
libWarn(attr, "voltage_map missing voltage.\n");
|
||||
}
|
||||
else
|
||||
libWarn(attr, "voltage_map supply name is not a string.\n");
|
||||
}
|
||||
else
|
||||
libWarn(attr, "voltage_map missing supply name and voltage.\n");
|
||||
}
|
||||
else
|
||||
libWarn(attr, "voltage_map missing values suffix.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitNomTemp(LibertyAttr *attr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ public:
|
|||
float &scale_var,
|
||||
Unit *unit_suffix);
|
||||
virtual void visitDelayModel(LibertyAttr *attr);
|
||||
virtual void visitVoltageMap(LibertyAttr *attr);
|
||||
virtual void visitBusStyle(LibertyAttr *attr);
|
||||
virtual void visitNomTemp(LibertyAttr *attr);
|
||||
virtual void visitNomVolt(LibertyAttr *attr);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "Clock.hh"
|
||||
#include "Tag.hh"
|
||||
#include "Corner.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "PathAnalysisPt.hh"
|
||||
#include "PathRef.hh"
|
||||
#include "Path.hh"
|
||||
|
|
@ -97,6 +98,19 @@ Path::pathAnalysisPtIndex(const StaState *sta) const
|
|||
return pathAnalysisPt(sta)->index();
|
||||
}
|
||||
|
||||
DcalcAnalysisPt *
|
||||
Path::dcalcAnalysisPt(const StaState *sta) const
|
||||
{
|
||||
return pathAnalysisPt(sta)->dcalcAnalysisPt();
|
||||
}
|
||||
|
||||
Slew
|
||||
Path::slew(const StaState *sta) const
|
||||
{
|
||||
return sta->graph()->slew(vertex(sta), transition(sta),
|
||||
dcalcAnalysisPt(sta)->index());
|
||||
}
|
||||
|
||||
int
|
||||
Path::trIndex(const StaState *sta) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
class DcalcAnalysisPt;
|
||||
|
||||
// Abstract base class for Path API.
|
||||
class Path
|
||||
{
|
||||
|
|
@ -55,6 +57,7 @@ public:
|
|||
virtual const MinMax *minMax(const StaState *sta) const;
|
||||
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const = 0;
|
||||
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
|
||||
virtual DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const;
|
||||
virtual Arrival arrival(const StaState *sta) const = 0;
|
||||
virtual void setArrival(Arrival arrival,
|
||||
const StaState *sta) = 0;
|
||||
|
|
@ -66,6 +69,7 @@ public:
|
|||
virtual void initRequired(const StaState *sta);
|
||||
virtual bool requiredIsInitValue(const StaState *sta) const;
|
||||
virtual Slack slack(const StaState *sta) const;
|
||||
virtual Slew slew(const StaState *sta) const;
|
||||
// This takes the same time as prevPath and prevArc combined.
|
||||
virtual void prevPath(const StaState *sta,
|
||||
// Return values.
|
||||
|
|
|
|||
|
|
@ -256,10 +256,63 @@ ReportPath::setDigits(int digits)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
ReportPath::reportPathEndHeader()
|
||||
{
|
||||
string header;
|
||||
switch (format_) {
|
||||
case report_path_full:
|
||||
case report_path_full_clock:
|
||||
case report_path_full_clock_expanded:
|
||||
case report_path_short:
|
||||
case report_path_endpoint:
|
||||
break;
|
||||
case report_path_summary:
|
||||
reportSummaryHeader(header);
|
||||
report_->print(header);
|
||||
break;
|
||||
case report_path_slack_only:
|
||||
reportSlackOnlyHeader(header);
|
||||
report_->print(header);
|
||||
break;
|
||||
default:
|
||||
internalError("unsupported path type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathEndFooter()
|
||||
{
|
||||
string header;
|
||||
switch (format_) {
|
||||
case report_path_full:
|
||||
case report_path_full_clock:
|
||||
case report_path_full_clock_expanded:
|
||||
case report_path_short:
|
||||
break;
|
||||
case report_path_endpoint:
|
||||
case report_path_summary:
|
||||
case report_path_slack_only:
|
||||
report_->print("\n");
|
||||
break;
|
||||
default:
|
||||
internalError("unsupported path type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathEnd(PathEnd *end)
|
||||
{
|
||||
string header, result;
|
||||
reportPathEnd(end, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathEnd(PathEnd *end,
|
||||
PathEnd *prev_end)
|
||||
{
|
||||
string result;
|
||||
switch (format_) {
|
||||
case report_path_full:
|
||||
case report_path_full_clock:
|
||||
|
|
@ -273,24 +326,18 @@ ReportPath::reportPathEnd(PathEnd *end)
|
|||
report_->print(result);
|
||||
report_->print("\n\n");
|
||||
break;
|
||||
case report_path_end:
|
||||
reportEndHeader(header);
|
||||
report_->print(header);
|
||||
case report_path_endpoint:
|
||||
reportEndpointHeader(end, prev_end);
|
||||
reportEndLine(end, result);
|
||||
report_->print(result);
|
||||
break;
|
||||
case report_path_summary:
|
||||
reportSummaryHeader(header);
|
||||
report_->print(header);
|
||||
reportSummaryLine(end, result);
|
||||
report_->print(result);
|
||||
break;
|
||||
case report_path_slack_only:
|
||||
reportSlackOnlyHeader(header);
|
||||
report_->print(header);
|
||||
reportSlackOnly(end, result);
|
||||
report_->print(result);
|
||||
report_->print("\n");
|
||||
break;
|
||||
default:
|
||||
internalError("unsupported path type");
|
||||
|
|
@ -301,89 +348,42 @@ ReportPath::reportPathEnd(PathEnd *end)
|
|||
void
|
||||
ReportPath::reportPathEnds(PathEndSeq *ends)
|
||||
{
|
||||
if (!ends->empty()) {
|
||||
string header;
|
||||
PathEndSeq::Iterator end_iter(ends);
|
||||
switch (format_) {
|
||||
case report_path_full:
|
||||
case report_path_full_clock:
|
||||
case report_path_full_clock_expanded:
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
string result;
|
||||
end->reportFull(this, result);
|
||||
report_->print(result);
|
||||
report_->print("\n\n");
|
||||
}
|
||||
break;
|
||||
case report_path_short:
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
string result;
|
||||
end->reportShort(this, result);
|
||||
report_->print(result);
|
||||
report_->print("\n\n");
|
||||
}
|
||||
break;
|
||||
case report_path_end:
|
||||
reportPathEndsEnd(ends);
|
||||
break;
|
||||
case report_path_summary:
|
||||
reportSummaryHeader(header);
|
||||
report_->print(header);
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
string result;
|
||||
reportSummaryLine(end, result);
|
||||
report_->print(result);
|
||||
}
|
||||
report_->print("\n");
|
||||
break;
|
||||
case report_path_slack_only:
|
||||
reportSlackOnlyHeader(header);
|
||||
report_->print(header);
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
string result;
|
||||
reportSlackOnly(end, result);
|
||||
report_->print(result);
|
||||
}
|
||||
report_->print("\n");
|
||||
break;
|
||||
default:
|
||||
internalError("unsupported path type");
|
||||
break;
|
||||
}
|
||||
reportPathEndHeader();
|
||||
PathEndSeq::Iterator end_iter(ends);
|
||||
PathEnd *prev_end = NULL;
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
reportEndpointHeader(end, prev_end);
|
||||
string result;
|
||||
end->reportFull(this, result);
|
||||
report_->print(result);
|
||||
report_->print("\n\n");
|
||||
prev_end = end;
|
||||
}
|
||||
reportPathEndFooter();
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathEndsEnd(PathEndSeq *ends)
|
||||
ReportPath::reportEndpointHeader(PathEnd *end,
|
||||
PathEnd *prev_end)
|
||||
{
|
||||
PathGroup *prev_group = NULL;
|
||||
PathEndSeq::Iterator end_iter(ends);
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *end = end_iter.next();
|
||||
PathGroup *group = search_->pathGroup(end);
|
||||
if (group != prev_group) {
|
||||
if (prev_group)
|
||||
report_->print("\n");
|
||||
const char *setup_hold = (end->minMax(this) == MinMax::min())
|
||||
? "min_delay/hold"
|
||||
: "max_delay/setup";
|
||||
report_->print("%s ('%s' group)\n\n",
|
||||
setup_hold,
|
||||
group->name());
|
||||
string header;
|
||||
reportEndHeader(header);
|
||||
report_->print(header);
|
||||
}
|
||||
string result;
|
||||
reportEndLine(end, result);
|
||||
report_->print(result);
|
||||
prev_group = group;
|
||||
if (prev_end)
|
||||
prev_group = search_->pathGroup(prev_end);
|
||||
PathGroup *group = search_->pathGroup(end);
|
||||
if (group != prev_group) {
|
||||
if (prev_group)
|
||||
report_->print("\n");
|
||||
const char *setup_hold = (end->minMax(this) == MinMax::min())
|
||||
? "min_delay/hold"
|
||||
: "max_delay/setup";
|
||||
report_->print("%s ('%s' group)\n\n",
|
||||
setup_hold,
|
||||
group->name());
|
||||
string header;
|
||||
reportEndHeader(header);
|
||||
report_->print(header);
|
||||
}
|
||||
report_->print("\n");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -81,7 +81,16 @@ public:
|
|||
void setNoSplit(bool no_split);
|
||||
ReportField *findField(const char *name);
|
||||
|
||||
// Header above reportPathEnd results.
|
||||
void reportPathEndHeader();
|
||||
// Footer below reportPathEnd results.
|
||||
void reportPathEndFooter();
|
||||
void reportPathEnd(PathEnd *end);
|
||||
// Format report_path_endpoint only:
|
||||
// Previous path end is used to detect path group changes
|
||||
// so headers are reported by group.
|
||||
void reportPathEnd(PathEnd *end,
|
||||
PathEnd *prev_end);
|
||||
void reportPathEnds(PathEndSeq *ends);
|
||||
void reportPath(const Path *path);
|
||||
|
||||
|
|
@ -194,7 +203,8 @@ protected:
|
|||
bool left_justify,
|
||||
Unit *unit,
|
||||
bool enabled);
|
||||
void reportPathEndsEnd(PathEndSeq *ends);
|
||||
void reportEndpointHeader(PathEnd *end,
|
||||
PathEnd *prev_end);
|
||||
void reportShort(const PathEndUnconstrained *end,
|
||||
PathExpanded &expanded,
|
||||
string &result);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ typedef enum {
|
|||
report_path_full_clock,
|
||||
report_path_full_clock_expanded,
|
||||
report_path_short,
|
||||
report_path_end,
|
||||
report_path_endpoint,
|
||||
report_path_summary,
|
||||
report_path_slack_only
|
||||
} ReportPathFormat;
|
||||
|
|
|
|||
|
|
@ -2465,6 +2465,31 @@ Sta::reportPathEnds(PathEndSeq *ends)
|
|||
report_path_->reportPathEnds(ends);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportPathEndHeader()
|
||||
{
|
||||
report_path_->reportPathEndHeader();
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportPathEndFooter()
|
||||
{
|
||||
report_path_->reportPathEndFooter();
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportPathEnd(PathEnd *end)
|
||||
{
|
||||
report_path_->reportPathEnd(end);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportPathEnd(PathEnd *end,
|
||||
PathEnd *prev_end)
|
||||
{
|
||||
report_path_->reportPathEnd(end, prev_end);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportPath(Path *path)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -870,6 +870,16 @@ public:
|
|||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
// Header above reportPathEnd results.
|
||||
void reportPathEndHeader();
|
||||
// Footer below reportPathEnd results.
|
||||
void reportPathEndFooter();
|
||||
// Format report_path_endpoint only:
|
||||
// Previous path end is used to detect path group changes
|
||||
// so headers are reported by group.
|
||||
void reportPathEnd(PathEnd *end,
|
||||
PathEnd *prev_end);
|
||||
void reportPathEnd(PathEnd *end);
|
||||
void reportPathEnds(PathEndSeq *ends);
|
||||
ReportPath *reportPath() { return report_path_; }
|
||||
void reportPath(Path *path);
|
||||
|
|
|
|||
20
tcl/Cmds.tcl
20
tcl/Cmds.tcl
|
|
@ -1793,6 +1793,8 @@ proc get_property_cmd { cmd type_key cmd_args } {
|
|||
return [liberty_library_property $object $attr]
|
||||
} elseif { $object_type == "Edge" } {
|
||||
return [edge_property $object $attr]
|
||||
} elseif { $object_type == "PathEnd" } {
|
||||
return [path_end_property $object $attr]
|
||||
} else {
|
||||
sta_error "$cmd unsupported object type $object_type."
|
||||
}
|
||||
|
|
@ -1835,6 +1837,24 @@ proc edge_property { edge property } {
|
|||
}
|
||||
}
|
||||
|
||||
proc path_end_property { path_end property } {
|
||||
if { $property == "startpoint" } {
|
||||
return [$path_end startpoint]
|
||||
} elseif { $property == "startpoint_clock" } {
|
||||
return [$path_end startpoint_clock]
|
||||
} elseif { $property == "endpoint" } {
|
||||
return [$path_end endpoint]
|
||||
} elseif { $property == "endpoint_clock" } {
|
||||
return [$path_end endpoint_clock]
|
||||
} elseif { $property == "endpoint_clock_pin" } {
|
||||
return [$path_end endpoint_clock_pin]
|
||||
} elseif { $property == "slack" } {
|
||||
return [time_sta_ui [$path_end slack]]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
proc get_object_type { obj } {
|
||||
set object_type [object_type $obj]
|
||||
if { $object_type == "Clock" } {
|
||||
|
|
|
|||
|
|
@ -383,5 +383,15 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } {
|
|||
}
|
||||
}
|
||||
|
||||
proc report_path_ends { path_ends } {
|
||||
report_path_end_header
|
||||
set prev_end "NULL"
|
||||
foreach path_end $path_ends {
|
||||
report_path_end2 $path_end $prev_end
|
||||
set prev_end $path_end
|
||||
}
|
||||
report_path_end_footer
|
||||
}
|
||||
|
||||
# sta namespace end.
|
||||
}
|
||||
|
|
|
|||
58
tcl/Sta.tcl
58
tcl/Sta.tcl
|
|
@ -138,7 +138,7 @@ proc_redirect report_clock_skew {
|
|||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_checks" \
|
||||
define_sta_cmd_args "find_timing_paths" \
|
||||
{[-from from_list|-rise_from from_list|-fall_from from_list]\
|
||||
[-through through_list|-rise_through through_list|-fall_through through_list]\
|
||||
[-to to_list|-rise_to to_list|-fall_to to_list]\
|
||||
|
|
@ -150,27 +150,22 @@ define_sta_cmd_args "report_checks" \
|
|||
[-slack_max slack_max]\
|
||||
[-slack_min slack_min]\
|
||||
[-sort_by_slack]\
|
||||
[-path_group group_name]\
|
||||
[-format full|full_clock|full_clock_expanded|short|end|summary]\
|
||||
[-fields [capacitance|transition_time|input_pin|net]]\
|
||||
[-digits digits]\
|
||||
[-no_line_splits]\
|
||||
[> filename] [>> filename]}
|
||||
[-path_group group_name]}
|
||||
|
||||
proc_redirect report_checks {
|
||||
global sta_report_unconstrained_paths
|
||||
variable path_options
|
||||
proc find_timing_paths { args } {
|
||||
set path_ends [find_timing_paths_cmd "find_timing_paths" args]
|
||||
return $path_ends
|
||||
}
|
||||
|
||||
parse_key_args "report_checks" args \
|
||||
proc find_timing_paths_cmd { cmd args_var } {
|
||||
upvar 1 $args_var args
|
||||
|
||||
parse_key_args "find_timing_paths" args \
|
||||
keys {-from -rise_from -fall_from -to -rise_to -fall_to \
|
||||
-path_delay -corner -group_count -endpoint_count \
|
||||
-slack_max -slack_min -path_group} \
|
||||
flags {-sort_by_slack -unique_paths_to_endpoint} 0
|
||||
|
||||
parse_report_path_options "report_checks" args "full" 0
|
||||
|
||||
set cmd "report_checks"
|
||||
|
||||
set min_max "max"
|
||||
set end_tr "rise_fall"
|
||||
if [info exists keys(-path_delay)] {
|
||||
|
|
@ -261,7 +256,36 @@ proc_redirect report_checks {
|
|||
$slack_min $slack_max \
|
||||
$sort_by_slack $groups \
|
||||
1 1 1 1 1 1]
|
||||
if { [$path_ends empty] } {
|
||||
return $path_ends
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_checks" \
|
||||
{[-from from_list|-rise_from from_list|-fall_from from_list]\
|
||||
[-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]\
|
||||
[-slack_max slack_max]\
|
||||
[-slack_min slack_min]\
|
||||
[-sort_by_slack]\
|
||||
[-path_group group_name]\
|
||||
[-format full|full_clock|full_clock_expanded|short|end|summary]\
|
||||
[-fields [capacitance|transition_time|input_pin|net]]\
|
||||
[-digits digits]\
|
||||
[-no_line_splits]\
|
||||
[> filename] [>> filename]}
|
||||
|
||||
proc_redirect report_checks {
|
||||
global sta_report_unconstrained_paths
|
||||
|
||||
parse_report_path_options "report_checks" args "full" 0
|
||||
set path_ends [find_timing_paths_cmd "report_checks" args]
|
||||
if { $path_ends == {} } {
|
||||
if { $sta_report_unconstrained_paths } {
|
||||
puts "No paths."
|
||||
} else {
|
||||
|
|
@ -270,7 +294,6 @@ proc_redirect report_checks {
|
|||
} else {
|
||||
report_path_ends $path_ends
|
||||
}
|
||||
delete_path_ends $path_ends
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
@ -398,7 +421,6 @@ proc_redirect report_check_types {
|
|||
$recovery $removal \
|
||||
$clk_gating_setup $clk_gating_hold]
|
||||
report_path_ends $path_ends
|
||||
delete_path_ends $path_ends
|
||||
}
|
||||
|
||||
if { $max_transition } {
|
||||
|
|
|
|||
117
tcl/StaTcl.i
117
tcl/StaTcl.i
|
|
@ -65,6 +65,7 @@
|
|||
#include "Tag.hh"
|
||||
#include "PathVertex.hh"
|
||||
#include "PathRef.hh"
|
||||
#include "PathExpanded.hh"
|
||||
#include "PathEnd.hh"
|
||||
#include "PathGroup.hh"
|
||||
#include "CheckTiming.hh"
|
||||
|
|
@ -96,7 +97,6 @@ typedef PinSet TmpPinSet;
|
|||
typedef PinSeq TmpPinSeq;
|
||||
typedef InstanceSeq TmpInstanceSeq;
|
||||
typedef InstanceSet TmpInstanceSet;
|
||||
typedef PathEndSeq::Iterator PathEndSeqIterator;
|
||||
typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator;
|
||||
typedef FloatSeq TmpFloatSeq;
|
||||
typedef string TmpString;
|
||||
|
|
@ -1596,7 +1596,7 @@ using namespace sta;
|
|||
else if (stringEq(arg, "short"))
|
||||
$1 = report_path_short;
|
||||
else if (stringEq(arg, "end"))
|
||||
$1 = report_path_end;
|
||||
$1 = report_path_endpoint;
|
||||
else if (stringEq(arg, "summary"))
|
||||
$1 = report_path_summary;
|
||||
else if (stringEq(arg, "slack_only"))
|
||||
|
|
@ -1779,11 +1779,17 @@ using namespace sta;
|
|||
%typemap(out) PathEndSeq* {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) PathEndSeqIterator* {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
Tcl_Obj *list = Tcl_NewListObj(0, NULL);
|
||||
const PathEndSeq *path_ends = $1;
|
||||
PathEndSeq::ConstIterator end_iter(path_ends);
|
||||
while (end_iter.hasNext()) {
|
||||
PathEnd *path_end = end_iter.next();
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj(path_end, SWIGTYPE_p_PathEnd, false);
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
}
|
||||
delete path_ends;
|
||||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
|
||||
%typemap(out) MinPulseWidthCheckSeqIterator* {
|
||||
|
|
@ -2196,20 +2202,6 @@ private:
|
|||
~PathEnd();
|
||||
};
|
||||
|
||||
class PathEndSeq
|
||||
{
|
||||
private:
|
||||
PathEnd();
|
||||
~PathEnd();
|
||||
};
|
||||
|
||||
class PathEndSeqIterator
|
||||
{
|
||||
private:
|
||||
PathEndSeqIterator();
|
||||
~PathEndSeqIterator();
|
||||
};
|
||||
|
||||
class MinPulseWidthCheck
|
||||
{
|
||||
private:
|
||||
|
|
@ -4412,6 +4404,31 @@ find_path_ends(ExceptionFrom *from,
|
|||
return ends;
|
||||
}
|
||||
|
||||
void
|
||||
report_path_end_header()
|
||||
{
|
||||
Sta::sta()->reportPathEndHeader();
|
||||
}
|
||||
|
||||
void
|
||||
report_path_end_footer()
|
||||
{
|
||||
Sta::sta()->reportPathEndFooter();
|
||||
}
|
||||
|
||||
void
|
||||
report_path_end(PathEnd *end)
|
||||
{
|
||||
Sta::sta()->reportPathEnd(end);
|
||||
}
|
||||
|
||||
void
|
||||
report_path_end2(PathEnd *end,
|
||||
PathEnd *prev_end)
|
||||
{
|
||||
Sta::sta()->reportPathEnd(end, prev_end);
|
||||
}
|
||||
|
||||
void
|
||||
set_report_path_format(ReportPathFormat format)
|
||||
{
|
||||
|
|
@ -4463,18 +4480,6 @@ set_report_path_no_split(bool no_split)
|
|||
Sta::sta()->setReportPathNoSplit(no_split);
|
||||
}
|
||||
|
||||
void
|
||||
report_path_ends(PathEndSeq *ends)
|
||||
{
|
||||
Sta::sta()->reportPathEnds(ends);
|
||||
}
|
||||
|
||||
void
|
||||
delete_path_ends(PathEndSeq *ends)
|
||||
{
|
||||
delete ends;
|
||||
}
|
||||
|
||||
void
|
||||
delete_path_ref(PathRef *path)
|
||||
{
|
||||
|
|
@ -4504,12 +4509,6 @@ report_clk_skew(ClockSet *clks,
|
|||
delete clks;
|
||||
}
|
||||
|
||||
PathEndSeqIterator *
|
||||
path_end_seq_iterator(PathEndSeq *ends)
|
||||
{
|
||||
return new PathEndSeqIterator(ends);
|
||||
}
|
||||
|
||||
TmpPinSet *
|
||||
startpoints()
|
||||
{
|
||||
|
|
@ -6254,17 +6253,43 @@ Crpr common_clk_pessimism() { return self->commonClkPessimism(Sta::sta()); }
|
|||
TransRiseFall *target_clk_end_trans()
|
||||
{ return const_cast<TransRiseFall*>(self->targetClkEndTrans(Sta::sta())); }
|
||||
|
||||
Pin *
|
||||
startpoint()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
PathExpanded expanded(self->path(), sta);
|
||||
return expanded.startPath()->pin(sta);
|
||||
}
|
||||
|
||||
%extend PathEndSeq {
|
||||
bool empty() { return self->empty(); }
|
||||
} // PathEndSeq methods
|
||||
Clock *
|
||||
startpoint_clock()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
return self->path()->clock(sta);
|
||||
}
|
||||
|
||||
%extend PathEndSeqIterator {
|
||||
bool has_next() { return self->hasNext(); }
|
||||
PathEnd *next() { return self->next(); }
|
||||
void finish() { delete self; }
|
||||
} // PathEndSeqIterator methods
|
||||
Pin *
|
||||
endpoint()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
return self->path()->pin(sta);
|
||||
}
|
||||
|
||||
Clock *
|
||||
endpoint_clock()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
return self->targetClk(sta);
|
||||
}
|
||||
|
||||
Pin *
|
||||
endpoint_clock_pin()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
return self->targetClkPath()->pin(sta);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
%extend MinPulseWidthCheckSeqIterator {
|
||||
bool has_next() { return self->hasNext(); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue