6414 lines
137 KiB
OpenEdge ABL
6414 lines
137 KiB
OpenEdge ABL
%module sta
|
|
|
|
%{
|
|
|
|
// OpenSTA, Static Timing Analyzer
|
|
// Copyright (c) 2022, Parallax Software, Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Most of the TCL SWIG interface code is in this file. This and any
|
|
// optional interface code is %included into a final interface file
|
|
// used by the application.
|
|
//
|
|
// Define TCL methods for each network object. This works despite the
|
|
// fact that the underlying implementation does not have class methods
|
|
// corresponding to the TCL methods defined here.
|
|
//
|
|
// Note the function name changes from sta naming convention
|
|
// (lower/capitalize) to TCL naming convention (lower/underscore).
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include <limits>
|
|
|
|
#include "Machine.hh"
|
|
#include "StaConfig.hh" // STA_VERSION
|
|
#include "Stats.hh"
|
|
#include "Report.hh"
|
|
#include "Error.hh"
|
|
#include "StringUtil.hh"
|
|
#include "PatternMatch.hh"
|
|
#include "MinMax.hh"
|
|
#include "Fuzzy.hh"
|
|
#include "FuncExpr.hh"
|
|
#include "Units.hh"
|
|
#include "Transition.hh"
|
|
#include "TimingRole.hh"
|
|
#include "TimingArc.hh"
|
|
#include "Liberty.hh"
|
|
#include "LibertyWriter.hh"
|
|
#include "EquivCells.hh"
|
|
#include "Wireload.hh"
|
|
#include "PortDirection.hh"
|
|
#include "Network.hh"
|
|
#include "Clock.hh"
|
|
#include "PortDelay.hh"
|
|
#include "ExceptionPath.hh"
|
|
#include "Sdc.hh"
|
|
#include "Graph.hh"
|
|
#include "Parasitics.hh"
|
|
#include "DelayCalc.hh"
|
|
#include "DcalcAnalysisPt.hh"
|
|
#include "Corner.hh"
|
|
#include "PathVertex.hh"
|
|
#include "PathRef.hh"
|
|
#include "PathExpanded.hh"
|
|
#include "PathEnd.hh"
|
|
#include "PathGroup.hh"
|
|
#include "PathAnalysisPt.hh"
|
|
#include "Property.hh"
|
|
#include "WritePathSpice.hh"
|
|
#include "Search.hh"
|
|
#include "Sta.hh"
|
|
#include "search/Tag.hh"
|
|
#include "search/CheckTiming.hh"
|
|
#include "search/CheckMinPulseWidths.hh"
|
|
#include "search/Levelize.hh"
|
|
#include "search/ReportPath.hh"
|
|
|
|
namespace sta {
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// C++ helper functions used by the interface functions.
|
|
// These are not visible in the TCL API.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
typedef Vector<Library*> LibrarySeq;
|
|
typedef CellSeq TmpCellSeq;
|
|
typedef LibertyCellSeq TmpLibertyCellSeq;
|
|
typedef PortSeq TmpPortSeq;
|
|
typedef LibertyPortSeq TmpLibertyPortSeq;
|
|
typedef PinSet TmpPinSet;
|
|
typedef PinSeq TmpPinSeq;
|
|
typedef InstanceSeq TmpInstanceSeq;
|
|
typedef InstanceSet TmpInstanceSet;
|
|
typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator;
|
|
typedef FloatSeq TmpFloatSeq;
|
|
typedef string TmpString;
|
|
typedef Set<const char*, CharPtrLess> StringSet;
|
|
typedef MinMaxAll MinMaxAllNull;
|
|
typedef ClockSet TmpClockSet;
|
|
typedef StringSeq TmpStringSeq;
|
|
|
|
using std::vector;
|
|
|
|
// Get the network for commands.
|
|
Network *
|
|
cmdNetwork()
|
|
{
|
|
return Sta::sta()->cmdNetwork();
|
|
}
|
|
|
|
// Make sure the network has been read and linked.
|
|
// Throwing an error means the caller doesn't have to check the result.
|
|
Network *
|
|
cmdLinkedNetwork()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
if (network->isLinked())
|
|
return network;
|
|
else {
|
|
Report *report = Sta::sta()->report();
|
|
report->error(201, "no network has been linked.");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Make sure an editable network has been read and linked.
|
|
NetworkEdit *
|
|
cmdEditNetwork()
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
if (network->isEditable())
|
|
return dynamic_cast<NetworkEdit*>(network);
|
|
else {
|
|
Report *report = Sta::sta()->report();
|
|
report->error(202, "network does not support edits.");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Get the graph for commands.
|
|
// Throw to cmd level on failure.
|
|
Graph *
|
|
cmdGraph()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->ensureGraph();
|
|
}
|
|
|
|
template <class TYPE>
|
|
Vector<TYPE> *
|
|
tclListSeq(Tcl_Obj *const source,
|
|
swig_type_info *swig_type,
|
|
Tcl_Interp *interp)
|
|
{
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
|
|
if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK
|
|
&& argc > 0) {
|
|
Vector<TYPE> *seq = new Vector<TYPE>;
|
|
for (int i = 0; i < argc; i++) {
|
|
void *obj;
|
|
// Ignore returned TCL_ERROR because can't get swig_type_info.
|
|
SWIG_ConvertPtr(argv[i], &obj, swig_type, false);
|
|
seq->push_back(reinterpret_cast<TYPE>(obj));
|
|
}
|
|
return seq;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
LibertyLibrarySeq *
|
|
tclListSeqLibertyLibrary(Tcl_Obj *const source,
|
|
Tcl_Interp *interp)
|
|
{
|
|
return tclListSeq<LibertyLibrary*>(source, SWIGTYPE_p_LibertyLibrary, interp);
|
|
}
|
|
|
|
vector<LibertyCell*> *
|
|
tclListSeqLibertyCell(Tcl_Obj *const source,
|
|
Tcl_Interp *interp)
|
|
{
|
|
return tclListSeq<LibertyCell*>(source, SWIGTYPE_p_LibertyCell, interp);
|
|
}
|
|
|
|
template <class TYPE>
|
|
Set<TYPE> *
|
|
tclListSet(Tcl_Obj *const source,
|
|
swig_type_info *swig_type,
|
|
Tcl_Interp *interp)
|
|
{
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
|
|
if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK
|
|
&& argc > 0) {
|
|
Set<TYPE> *set = new Set<TYPE>;
|
|
for (int i = 0; i < argc; i++) {
|
|
void *obj;
|
|
// Ignore returned TCL_ERROR because can't get swig_type_info.
|
|
SWIG_ConvertPtr(argv[i], &obj, swig_type, false);
|
|
set->insert(reinterpret_cast<TYPE>(obj));
|
|
}
|
|
return set;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
PinSet *
|
|
tclListSetPin(Tcl_Obj *const source,
|
|
Tcl_Interp *interp)
|
|
{
|
|
return tclListSet<Pin*>(source, SWIGTYPE_p_Pin, interp);
|
|
}
|
|
|
|
StringSet *
|
|
tclListSetConstChar(Tcl_Obj *const source,
|
|
Tcl_Interp *interp)
|
|
{
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
|
|
if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) {
|
|
StringSet *set = new StringSet;
|
|
for (int i = 0; i < argc; i++) {
|
|
int length;
|
|
const char *str = Tcl_GetStringFromObj(argv[i], &length);
|
|
set->insert(str);
|
|
}
|
|
return set;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
StringSeq *
|
|
tclListSeqConstChar(Tcl_Obj *const source,
|
|
Tcl_Interp *interp)
|
|
{
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
|
|
if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) {
|
|
StringSeq *seq = new StringSeq;
|
|
for (int i = 0; i < argc; i++) {
|
|
int length;
|
|
const char *str = Tcl_GetStringFromObj(argv[i], &length);
|
|
seq->push_back(str);
|
|
}
|
|
return seq;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TmpPinSet *
|
|
findStartpoints()
|
|
{
|
|
PinSet *pins = new PinSet;
|
|
VertexPinCollector visitor(pins);
|
|
Sta::sta()->visitStartpoints(&visitor);
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSet *
|
|
findEndpoints()
|
|
{
|
|
PinSet *pins = new PinSet;
|
|
VertexPinCollector visitor(pins);
|
|
Sta::sta()->visitEndpoints(&visitor);
|
|
return pins;
|
|
}
|
|
|
|
void
|
|
pushPowerResultFloats(PowerResult &power,
|
|
TmpFloatSeq *floats)
|
|
{
|
|
floats->push_back(power.internal());
|
|
floats->push_back(power.switching());
|
|
floats->push_back(power.leakage());
|
|
floats->push_back(power.total());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
tclArgError(Tcl_Interp *interp,
|
|
const char *msg,
|
|
const char *arg)
|
|
{
|
|
// Swig does not add try/catch around arg parsing so this cannot use Report::error.
|
|
string error_msg = "Error: ";
|
|
error_msg += msg;
|
|
char *error = stringPrint(error_msg.c_str(), arg);
|
|
Tcl_SetResult(interp, error, TCL_VOLATILE);
|
|
stringDelete(error);
|
|
}
|
|
|
|
void
|
|
objectListNext(const char *list,
|
|
const char *type,
|
|
// Return values.
|
|
bool &type_match,
|
|
const char *&next)
|
|
{
|
|
// Default return values (failure).
|
|
type_match = false;
|
|
next = nullptr;
|
|
// _hexaddress_p_type
|
|
const char *s = list;
|
|
char ch = *s++;
|
|
if (ch == '_') {
|
|
while (*s && isxdigit(*s))
|
|
s++;
|
|
if ((s - list - 1) == sizeof(void*) * 2
|
|
&& *s && *s++ == '_'
|
|
&& *s && *s++ == 'p'
|
|
&& *s && *s++ == '_') {
|
|
const char *t = type;
|
|
while (*s && *s != ' ') {
|
|
if (*s != *t)
|
|
return;
|
|
s++;
|
|
t++;
|
|
}
|
|
type_match = true;
|
|
if (*s)
|
|
next = s + 1;
|
|
else
|
|
next = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
using namespace sta;
|
|
|
|
%}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// SWIG type definitions.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// String that is deleted after crossing over to tcland.
|
|
%typemap(out) TmpString* {
|
|
string *str = $1;
|
|
if (str) {
|
|
// String is volatile because it is deleted.
|
|
Tcl_SetResult(interp, const_cast<char*>(str->c_str()), TCL_VOLATILE);
|
|
delete str;
|
|
}
|
|
else
|
|
Tcl_SetResult(interp, nullptr, TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) StringSeq* {
|
|
$1 = tclListSeqConstChar($input, interp);
|
|
}
|
|
|
|
%typemap(out) StringSeq* {
|
|
StringSeq *strs = $1;
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
StringSeq::Iterator str_iter(strs);
|
|
while (str_iter.hasNext()) {
|
|
const char *str = str_iter.next();
|
|
Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str));
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpStringSeq* {
|
|
StringSeq *strs = $1;
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
StringSeq::Iterator str_iter(strs);
|
|
while (str_iter.hasNext()) {
|
|
const char *str = str_iter.next();
|
|
Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str));
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
delete strs;
|
|
}
|
|
|
|
%typemap(out) Library* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibraryIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibertyLibraryIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Cell* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) CellSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
CellSeq *cells = $1;
|
|
CellSeq::Iterator cell_iter(cells);
|
|
while (cell_iter.hasNext()) {
|
|
Cell *cell = cell_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_Cell, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpCellSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
CellSeq *cells = $1;
|
|
CellSeq::Iterator cell_iter(cells);
|
|
while (cell_iter.hasNext()) {
|
|
Cell *cell = cell_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_Cell, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
delete cells;
|
|
}
|
|
|
|
%typemap(in) vector<LibertyCell*> * {
|
|
$1 = tclListSeqLibertyCell($input, interp);
|
|
}
|
|
|
|
%typemap(out) LibertyCellSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
LibertyCellSeq *cells = $1;
|
|
LibertyCellSeq::Iterator cell_iter(cells);
|
|
while (cell_iter.hasNext()) {
|
|
LibertyCell *cell = cell_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_LibertyCell,
|
|
false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpLibertyCellSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
LibertyCellSeq *cells = $1;
|
|
LibertyCellSeq::Iterator cell_iter(cells);
|
|
while (cell_iter.hasNext()) {
|
|
LibertyCell *cell = cell_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(cell, SWIGTYPE_p_LibertyCell,
|
|
false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
delete cells;
|
|
}
|
|
|
|
%typemap(out) CellPortIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibertyCellPortIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Port* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(in) PortSet* {
|
|
$1 = tclListSet<Port*>($input, SWIGTYPE_p_Port, interp);
|
|
}
|
|
|
|
%typemap(in) PortSeq* {
|
|
$1 = tclListSeq<Port*>($input, SWIGTYPE_p_Port, interp);
|
|
}
|
|
|
|
%typemap(out) TmpPortSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
TmpPortSeq *ports = $1;
|
|
TmpPortSeq::Iterator port_iter(ports);
|
|
while (port_iter.hasNext()) {
|
|
Port *port = port_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(port, SWIGTYPE_p_Port, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete ports;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpLibertyPortSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
TmpLibertyPortSeq *ports = $1;
|
|
TmpLibertyPortSeq::Iterator port_iter(ports);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(port, SWIGTYPE_p_LibertyPort,
|
|
false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete ports;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpPinSet* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PinSet *pins = $1;
|
|
PinSet::Iterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete pins;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpPinSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PinSeq *pins = $1;
|
|
PinSeq::Iterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete pins;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) PortMemberIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibertyCell* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibertyPort* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LibertyPortMemberIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1,
|
|
SWIGTYPE_p_LibertyPortMemberIterator,
|
|
false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) TimingArc* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) const TimingArcSetSeq& {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const TimingArcSetSeq *arc_sets = $1;
|
|
for (TimingArcSet *arc_set : *arc_sets) {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(arc_set, SWIGTYPE_p_TimingArcSet, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) const TimingArcSeq& {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const TimingArcSeq *arcs = $1;
|
|
for (TimingArc *arc : *arcs) {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(arc, SWIGTYPE_p_TimingArc, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) Wireload* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) WireloadSelection* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(in) Transition* {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
Transition *tr = Transition::find(arg);
|
|
if (tr == nullptr) {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: transition not found."),
|
|
TCL_STATIC);
|
|
return TCL_ERROR;
|
|
}
|
|
else
|
|
$1 = tr;
|
|
}
|
|
|
|
%typemap(out) Transition* {
|
|
Transition *tr = $1;
|
|
const char *str = "";
|
|
if (tr)
|
|
str = tr->asString();
|
|
Tcl_SetResult(interp, const_cast<char*>(str), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) RiseFall* {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
RiseFall *tr = RiseFall::find(arg);
|
|
if (tr == nullptr) {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: unknown transition name."),
|
|
TCL_STATIC);
|
|
return TCL_ERROR;
|
|
}
|
|
$1 = tr;
|
|
}
|
|
|
|
%typemap(out) RiseFall* {
|
|
const RiseFall *tr = $1;
|
|
const char *str = "";
|
|
if (tr)
|
|
str = tr->asString();
|
|
Tcl_SetResult(interp, const_cast<char*>(str), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) RiseFallBoth* {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
RiseFallBoth *tr = RiseFallBoth::find(arg);
|
|
if (tr == nullptr) {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: unknown transition name."),
|
|
TCL_STATIC);
|
|
return TCL_ERROR;
|
|
}
|
|
$1 = tr;
|
|
}
|
|
|
|
%typemap(out) RiseFallBoth* {
|
|
RiseFallBoth *tr = $1;
|
|
const char *str = "";
|
|
if (tr)
|
|
str = tr->asString();
|
|
Tcl_SetResult(interp, const_cast<char*>(str), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) TimingRole* {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
TimingRole *role = TimingRole::find(arg);
|
|
if (role)
|
|
$1 = TimingRole::find(arg);
|
|
else {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: unknown timing role."),
|
|
TCL_STATIC);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(out) TimingRole* {
|
|
Tcl_SetResult(interp, const_cast<char*>($1->asString()), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) LogicValue {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "0") || stringEq(arg, "zero"))
|
|
$1 = LogicValue::zero;
|
|
else if (stringEq(arg, "1") || stringEq(arg, "one"))
|
|
$1 = LogicValue::one;
|
|
else if (stringEq(arg, "X"))
|
|
$1 = LogicValue::unknown;
|
|
else if (stringEq(arg, "rise") || stringEq(arg, "rising"))
|
|
$1 = LogicValue::rise;
|
|
else if (stringEq(arg, "fall") || stringEq(arg, "falling"))
|
|
$1 = LogicValue::fall;
|
|
else {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: unknown logic value."),
|
|
TCL_STATIC);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) AnalysisType {
|
|
int length;
|
|
const char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEqual(arg, "single"))
|
|
$1 = AnalysisType::single;
|
|
else if (stringEqual(arg, "bc_wc"))
|
|
$1 = AnalysisType::bc_wc;
|
|
else if (stringEq(arg, "on_chip_variation"))
|
|
$1 = AnalysisType::ocv;
|
|
else {
|
|
Tcl_SetResult(interp,const_cast<char*>("Error: unknown analysis type."),
|
|
TCL_STATIC);
|
|
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(out) Instance* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(in) InstanceSeq* {
|
|
$1 = tclListSeq<Instance*>($input, SWIGTYPE_p_Instance, interp);
|
|
}
|
|
|
|
%typemap(out) TmpInstanceSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
TmpInstanceSeq *insts = $1;
|
|
TmpInstanceSeq::Iterator inst_iter(insts);
|
|
while (inst_iter.hasNext()) {
|
|
Instance *inst = inst_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(inst, SWIGTYPE_p_Instance,false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete insts;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) InstanceChildIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) LeafInstanceIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) InstancePinIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) InstanceNetIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Pin* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) PinSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PinSeq *pins = $1;
|
|
PinSeq::Iterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete pins;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) Net* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) NetSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
NetSeq *nets = $1;
|
|
NetSeq::Iterator net_iter(nets);
|
|
while (net_iter.hasNext()) {
|
|
Net *net = net_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(net, SWIGTYPE_p_Net, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete nets;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) NetPinIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) NetTermIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) NetConnectedPinIterator* {
|
|
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) PinConnectedPinIterator* {
|
|
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Clock* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) ClockSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
ClockSeq *clks = $1;
|
|
ClockSeq::Iterator clk_iter(clks);
|
|
while (clk_iter.hasNext()) {
|
|
Clock *clk = clk_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete clks;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) ClockIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) ClockEdge* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1,$1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(in) FloatSeq* {
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
FloatSeq *floats = nullptr;
|
|
|
|
if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) {
|
|
if (argc)
|
|
floats = new FloatSeq;
|
|
for (int i = 0; i < argc; i++) {
|
|
char *arg = Tcl_GetString(argv[i]);
|
|
double value;
|
|
if (Tcl_GetDouble(interp, arg, &value) == TCL_OK)
|
|
floats->push_back(static_cast<float>(value));
|
|
else {
|
|
delete floats;
|
|
tclArgError(interp, "%s is not a floating point number.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
$1 = floats;
|
|
}
|
|
|
|
%typemap(out) FloatSeq* {
|
|
FloatSeq *floats = $1;
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
if (floats) {
|
|
for (unsigned i = 0; i < floats->size(); i++) {
|
|
Tcl_Obj *obj = Tcl_NewDoubleObj((*floats)[i]);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpFloatSeq* {
|
|
FloatSeq *floats = $1;
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
if (floats) {
|
|
for (unsigned i = 0; i < floats->size(); i++) {
|
|
Tcl_Obj *obj = Tcl_NewDoubleObj((*floats)[i]);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete floats;
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(in) IntSeq* {
|
|
int argc;
|
|
Tcl_Obj **argv;
|
|
IntSeq *ints = nullptr;
|
|
|
|
if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) {
|
|
if (argc)
|
|
ints = new IntSeq;
|
|
for (int i = 0; i < argc; i++) {
|
|
char *arg = Tcl_GetString(argv[i]);
|
|
int value;
|
|
if (Tcl_GetInt(interp, arg, &value) == TCL_OK)
|
|
ints->push_back(value);
|
|
else {
|
|
delete ints;
|
|
tclArgError(interp, "%s is not an integer.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
$1 = ints;
|
|
}
|
|
|
|
%typemap(in) MinMax* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
MinMax *min_max = MinMax::find(arg);
|
|
if (min_max)
|
|
$1 = min_max;
|
|
else {
|
|
tclArgError(interp, "%s not min or max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(out) MinMax* {
|
|
Tcl_SetResult(interp, const_cast<char*>($1->asString()), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(out) MinMax* {
|
|
Tcl_SetResult(interp, const_cast<char*>($1->asString()), TCL_STATIC);
|
|
}
|
|
|
|
%typemap(in) MinMaxAll* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
MinMaxAll *min_max = MinMaxAll::find(arg);
|
|
if (min_max)
|
|
$1 = min_max;
|
|
else {
|
|
tclArgError(interp, "%s not min, max or min_max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) MinMaxAllNull* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEqual(arg, "NULL"))
|
|
$1 = nullptr;
|
|
else {
|
|
MinMaxAll *min_max = MinMaxAll::find(arg);
|
|
if (min_max)
|
|
$1 = min_max;
|
|
else {
|
|
tclArgError(interp, "%s not min, max or min_max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
%typemap(out) MinMaxAll* {
|
|
Tcl_SetResult(interp, const_cast<char*>($1->asString()), TCL_STATIC);
|
|
}
|
|
|
|
// SetupHold is typedef'd to MinMax.
|
|
%typemap(in) SetupHold* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEqual(arg, "hold")
|
|
|| stringEqual(arg, "min"))
|
|
$1 = MinMax::min();
|
|
else if (stringEqual(arg, "setup")
|
|
|| stringEqual(arg, "max"))
|
|
$1 = MinMax::max();
|
|
else {
|
|
tclArgError(interp, "%s not setup, hold, min or max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
// SetupHoldAll is typedef'd to MinMaxAll.
|
|
%typemap(in) SetupHoldAll* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEqual(arg, "hold")
|
|
|| stringEqual(arg, "min"))
|
|
$1 = SetupHoldAll::min();
|
|
else if (stringEqual(arg, "setup")
|
|
|| stringEqual(arg, "max"))
|
|
$1 = SetupHoldAll::max();
|
|
else if (stringEqual(arg, "setup_hold")
|
|
|| stringEqual(arg, "min_max"))
|
|
$1 = SetupHoldAll::all();
|
|
else {
|
|
tclArgError(interp, "%s not setup, hold, setup_hold, min, max or min_max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
// EarlyLate is typedef'd to MinMax.
|
|
%typemap(in) EarlyLate* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
EarlyLate *early_late = EarlyLate::find(arg);
|
|
if (early_late)
|
|
$1 = early_late;
|
|
else {
|
|
tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
// EarlyLateAll is typedef'd to MinMaxAll.
|
|
%typemap(in) EarlyLateAll* {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
EarlyLateAll *early_late = EarlyLateAll::find(arg);
|
|
if (early_late)
|
|
$1 = early_late;
|
|
else {
|
|
tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) TimingDerateType {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "net_delay"))
|
|
$1 = TimingDerateType::net_delay;
|
|
else if (stringEq(arg, "cell_delay"))
|
|
$1 = TimingDerateType::cell_delay;
|
|
else if (stringEq(arg, "cell_check"))
|
|
$1 = TimingDerateType::cell_check;
|
|
else {
|
|
tclArgError(interp, "%s not net_delay, cell_delay or cell_check.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) TimingDerateCellType {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "cell_delay"))
|
|
$1 = TimingDerateCellType::cell_delay;
|
|
else if (stringEq(arg, "cell_check"))
|
|
$1 = TimingDerateCellType::cell_check;
|
|
else {
|
|
tclArgError(interp, "%s not cell_delay or cell_check.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) PathClkOrData {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "clk"))
|
|
$1 = PathClkOrData::clk;
|
|
else if (stringEq(arg, "data"))
|
|
$1 = PathClkOrData::data;
|
|
else {
|
|
tclArgError(interp, "%s not clk or data.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) ReportSortBy {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "group"))
|
|
$1 = sort_by_group;
|
|
else if (stringEq(arg, "slack"))
|
|
$1 = sort_by_slack;
|
|
else {
|
|
tclArgError(interp, "%s not group or slack.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) ReportPathFormat {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "full"))
|
|
$1 = ReportPathFormat::full;
|
|
else if (stringEq(arg, "full_clock"))
|
|
$1 = ReportPathFormat::full_clock;
|
|
else if (stringEq(arg, "full_clock_expanded"))
|
|
$1 = ReportPathFormat::full_clock_expanded;
|
|
else if (stringEq(arg, "short"))
|
|
$1 = ReportPathFormat::shorter;
|
|
else if (stringEq(arg, "end"))
|
|
$1 = ReportPathFormat::endpoint;
|
|
else if (stringEq(arg, "summary"))
|
|
$1 = ReportPathFormat::summary;
|
|
else if (stringEq(arg, "slack_only"))
|
|
$1 = ReportPathFormat::slack_only;
|
|
else if (stringEq(arg, "json"))
|
|
$1 = ReportPathFormat::json;
|
|
else {
|
|
tclArgError(interp, "unknown path type %s.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(in) PinSeq* {
|
|
$1 = tclListSeq<Pin*>($input, SWIGTYPE_p_Pin, interp);
|
|
}
|
|
|
|
%typemap(in) PinSet* {
|
|
$1 = tclListSetPin($input, interp);
|
|
}
|
|
|
|
%typemap(out) PinSet* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const PinSet *pins = $1;
|
|
if (pins) {
|
|
PinSet::ConstIterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) PinSet& {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const PinSet *pins = $1;
|
|
if (pins) {
|
|
PinSet::ConstIterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(in) ClockSet* {
|
|
$1 = tclListSet<Clock*>($input, SWIGTYPE_p_Clock, interp);
|
|
}
|
|
|
|
%typemap(out) ClockSet* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const ClockSet *clks = $1;
|
|
if (clks) {
|
|
ClockSet::ConstIterator clk_iter(clks);
|
|
while (clk_iter.hasNext()) {
|
|
Clock *clk = clk_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) TmpClockSet* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
const ClockSet *clks = $1;
|
|
if (clks) {
|
|
ClockSet::ConstIterator clk_iter(clks);
|
|
while (clk_iter.hasNext()) {
|
|
Clock *clk = clk_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete clks;
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(in) InstanceSet* {
|
|
$1 = tclListSet<Instance*>($input, SWIGTYPE_p_Instance, interp);
|
|
}
|
|
|
|
%typemap(out) TmpInstanceSet* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
InstanceSet *insts = $1;
|
|
InstanceSet::Iterator inst_iter(insts);
|
|
while (inst_iter.hasNext()) {
|
|
Instance *inst = inst_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(inst, SWIGTYPE_p_Instance,false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete insts;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(in) NetSet* {
|
|
$1 = tclListSet<Net*>($input, SWIGTYPE_p_Net, interp);
|
|
}
|
|
|
|
%typemap(in) ExceptionThruSeq* {
|
|
$1 = tclListSeq<ExceptionThru*>($input, SWIGTYPE_p_ExceptionThru, interp);
|
|
}
|
|
|
|
%typemap(out) Vertex* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Vertex** {
|
|
int i = 0;
|
|
Tcl_ResetResult(interp);
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
while ($1[i]) {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1[i], SWIGTYPE_p_Vertex,false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
i++;
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(in) EdgeSeq* {
|
|
$1 = tclListSeq<Edge*>($input, SWIGTYPE_p_Edge, interp);
|
|
}
|
|
|
|
%typemap(out) Edge* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) EdgeSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
EdgeSeq *edges = $1;
|
|
EdgeSeq::Iterator edge_iter(edges);
|
|
while (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(edge, SWIGTYPE_p_Edge, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
delete edges;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) VertexIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) VertexInEdgeIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) VertexOutEdgeIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) CheckErrorSeq & {
|
|
Tcl_Obj *error_list = Tcl_NewListObj(0, nullptr);
|
|
CheckErrorSeq *check_errors = $1;
|
|
CheckErrorSeq::Iterator check_iter(check_errors);
|
|
while (check_iter.hasNext()) {
|
|
CheckError *error = check_iter.next();
|
|
Tcl_Obj *string_list = Tcl_NewListObj(0, nullptr);
|
|
CheckError::Iterator string_iter(error);
|
|
while (string_iter.hasNext()) {
|
|
const char *str = string_iter.next();
|
|
size_t str_len = strlen(str);
|
|
Tcl_Obj *obj = Tcl_NewStringObj(const_cast<char*>(str),
|
|
static_cast<int>(str_len));
|
|
Tcl_ListObjAppendElement(interp, string_list, obj);
|
|
}
|
|
Tcl_ListObjAppendElement(interp, error_list, string_list);
|
|
}
|
|
Tcl_SetObjResult(interp, error_list);
|
|
}
|
|
|
|
%typemap(out) PathEnd* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) PathEndSeq* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
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 the PathEndSeq, not the ends.
|
|
delete path_ends;
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) MinPulseWidthCheckSeqIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) PathRefSeq* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PathRefSeq *paths = $1;
|
|
PathRefSeq::Iterator path_iter(paths);
|
|
while (path_iter.hasNext()) {
|
|
PathRef *path = &path_iter.next();
|
|
PathRef *copy = new PathRef(path);
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) MinPulseWidthCheck* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) MinPulseWidthCheckSeq & {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) MinPulseWidthCheckSeqIterator & {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) VertexPathIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) SlowDrvrIterator* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) ExceptionFrom* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) ExceptionTo* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) ExceptionThru* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) OperatingConditions* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(in) ReducedParasiticType {
|
|
int length;
|
|
char *arg = Tcl_GetStringFromObj($input, &length);
|
|
if (stringEq(arg, "pi_elmore"))
|
|
$1 = ReducedParasiticType::pi_elmore;
|
|
else if (stringEq(arg, "pi_pole_residue2"))
|
|
$1 = ReducedParasiticType::pi_pole_residue2;
|
|
else if (stringEq(arg, "none"))
|
|
$1 = ReducedParasiticType::none;
|
|
else {
|
|
tclArgError(interp, "%s pi_elmore, pi_pole_residue2, or none.", arg);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
%typemap(out) Arrival {
|
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
|
}
|
|
|
|
%typemap(out) Required {
|
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
|
}
|
|
|
|
%typemap(out) Slack {
|
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
|
}
|
|
|
|
%typemap(out) ArcDelay {
|
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
|
}
|
|
|
|
%typemap(out) Slew {
|
|
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
|
}
|
|
|
|
%typemap(in) PathGroupNameSet* {
|
|
$1 = tclListSetConstChar($input, interp);
|
|
}
|
|
|
|
%typemap(in) StringSet* {
|
|
$1 = tclListSetConstChar($input, interp);
|
|
}
|
|
|
|
%typemap(out) Corner* {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
|
|
%typemap(out) Corners* {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
Corners *corners = $1;
|
|
for (Corner *corner : *corners) {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(corner, SWIGTYPE_p_Corner, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
|
|
%typemap(out) PropertyValue {
|
|
PropertyValue value = $1;
|
|
switch (value.type()) {
|
|
case PropertyValue::Type::type_none:
|
|
Tcl_SetResult(interp, const_cast<char*>(""), TCL_STATIC);
|
|
break;
|
|
case PropertyValue::Type::type_string:
|
|
Tcl_SetResult(interp, const_cast<char*>(value.stringValue()), TCL_VOLATILE);
|
|
break;
|
|
case PropertyValue::Type::type_float: {
|
|
const Unit *unit = value.unit();
|
|
const char *float_string = unit->asString(value.floatValue(), 6);
|
|
Tcl_SetResult(interp, const_cast<char*>(float_string), TCL_VOLATILE);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_bool: {
|
|
const char *bool_string = value.boolValue() ? "1" : "0";
|
|
Tcl_SetResult(interp, const_cast<char*>(bool_string), TCL_STATIC);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_library: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.library(),
|
|
SWIGTYPE_p_Library, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_cell: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.cell(),
|
|
SWIGTYPE_p_Cell, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_port: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.port(),
|
|
SWIGTYPE_p_Port, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_liberty_library: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyLibrary(),
|
|
SWIGTYPE_p_LibertyLibrary, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_liberty_cell: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyCell(),
|
|
SWIGTYPE_p_LibertyCell, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_liberty_port: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyPort(),
|
|
SWIGTYPE_p_LibertyPort, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_instance: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.instance(),
|
|
SWIGTYPE_p_Instance, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_pin: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.pin(), SWIGTYPE_p_Pin, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_pins: {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PinSeq *pins = value.pins();
|
|
PinSeq::Iterator pin_iter(pins);
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(pin, SWIGTYPE_p_Pin, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_net: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.net(),
|
|
SWIGTYPE_p_Net, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_clk: {
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(value.clock(),
|
|
SWIGTYPE_p_Clock, false);
|
|
Tcl_SetObjResult(interp, obj);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_clks: {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
ClockSeq *clks = value.clocks();
|
|
ClockSeq::Iterator clk_iter(clks);
|
|
while (clk_iter.hasNext()) {
|
|
Clock *clk = clk_iter.next();
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_path_refs: {
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
PathRefSeq *paths = value.pathRefs();
|
|
PathRefSeq::Iterator path_iter(paths);
|
|
while (path_iter.hasNext()) {
|
|
PathRef &path = path_iter.next();
|
|
PathRef *copy = new PathRef(path);
|
|
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
}
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
break;
|
|
case PropertyValue::Type::type_pwr_activity: {
|
|
PwrActivity activity = value.pwrActivity();
|
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
|
Tcl_Obj *obj;
|
|
const char *str;
|
|
|
|
str = stringPrintTmp("%.5e", activity.activity());
|
|
obj = Tcl_NewStringObj(str, strlen(str));
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
str = stringPrintTmp("%.3f", activity.duty());
|
|
obj = Tcl_NewStringObj(str, strlen(str));
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
str = activity.originName();
|
|
obj = Tcl_NewStringObj(str, strlen(str));
|
|
Tcl_ListObjAppendElement(interp, list, obj);
|
|
|
|
Tcl_SetObjResult(interp, list);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Empty class definitions to make swig happy.
|
|
// Private constructor/destructor so swig doesn't emit them.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class Library
|
|
{
|
|
private:
|
|
Library();
|
|
~Library();
|
|
};
|
|
|
|
class LibraryIterator
|
|
{
|
|
private:
|
|
LibraryIterator();
|
|
~LibraryIterator();
|
|
};
|
|
|
|
class Cell
|
|
{
|
|
private:
|
|
Cell();
|
|
~Cell();
|
|
};
|
|
|
|
class CellPortIterator
|
|
{
|
|
private:
|
|
CellPortIterator();
|
|
~CellPortIterator();
|
|
};
|
|
|
|
class LibertyCellPortIterator
|
|
{
|
|
private:
|
|
LibertyCellPortIterator();
|
|
~LibertyCellPortIterator();
|
|
};
|
|
|
|
class Port
|
|
{
|
|
private:
|
|
Port();
|
|
~Port();
|
|
};
|
|
|
|
class PortMemberIterator
|
|
{
|
|
private:
|
|
PortMemberIterator();
|
|
~PortMemberIterator();
|
|
};
|
|
|
|
class LibertyLibrary
|
|
{
|
|
private:
|
|
LibertyLibrary();
|
|
~LibertyLibrary();
|
|
};
|
|
|
|
class LibertyLibraryIterator
|
|
{
|
|
private:
|
|
LibertyLibraryIterator();
|
|
~LibertyLibraryIterator();
|
|
};
|
|
|
|
class LibertyCell
|
|
{
|
|
private:
|
|
LibertyCell();
|
|
~LibertyCell();
|
|
};
|
|
|
|
class LibertyPort
|
|
{
|
|
private:
|
|
LibertyPort();
|
|
~LibertyPort();
|
|
};
|
|
|
|
class LibertyPortMemberIterator
|
|
{
|
|
private:
|
|
LibertyPortMemberIterator();
|
|
~LibertyPortMemberIterator();
|
|
};
|
|
|
|
class TimingArcSet
|
|
{
|
|
private:
|
|
TimingArcSet();
|
|
~TimingArcSet();
|
|
};
|
|
|
|
class TimingArc
|
|
{
|
|
private:
|
|
TimingArc();
|
|
~TimingArc();
|
|
};
|
|
|
|
class Wireload
|
|
{
|
|
private:
|
|
Wireload();
|
|
~Wireload();
|
|
};
|
|
|
|
class WireloadSelection
|
|
{
|
|
private:
|
|
WireloadSelection();
|
|
~WireloadSelection();
|
|
};
|
|
|
|
class Transition
|
|
{
|
|
private:
|
|
Transition();
|
|
~Transition();
|
|
};
|
|
|
|
class Instance
|
|
{
|
|
private:
|
|
Instance();
|
|
~Instance();
|
|
};
|
|
|
|
class Pin
|
|
{
|
|
private:
|
|
Pin();
|
|
~Pin();
|
|
};
|
|
|
|
class Term
|
|
{
|
|
private:
|
|
Term();
|
|
~Term();
|
|
};
|
|
|
|
class InstanceChildIterator
|
|
{
|
|
private:
|
|
InstanceChildIterator();
|
|
~InstanceChildIterator();
|
|
};
|
|
|
|
class InstancePinIterator
|
|
{
|
|
private:
|
|
InstancePinIterator();
|
|
~InstancePinIterator();
|
|
};
|
|
|
|
class InstanceNetIterator
|
|
{
|
|
private:
|
|
InstanceNetIterator();
|
|
~InstanceNetIterator();
|
|
};
|
|
|
|
class LeafInstanceIterator
|
|
{
|
|
private:
|
|
LeafInstanceIterator();
|
|
~LeafInstanceIterator();
|
|
};
|
|
|
|
class Net
|
|
{
|
|
private:
|
|
Net();
|
|
~Net();
|
|
};
|
|
|
|
class NetPinIterator
|
|
{
|
|
private:
|
|
NetPinIterator();
|
|
~NetPinIterator();
|
|
};
|
|
|
|
class NetTermIterator
|
|
{
|
|
private:
|
|
NetTermIterator();
|
|
~NetTermIterator();
|
|
};
|
|
|
|
class NetConnectedPinIterator
|
|
{
|
|
private:
|
|
NetConnectedPinIterator();
|
|
~NetConnectedPinIterator();
|
|
};
|
|
|
|
class PinConnectedPinIterator
|
|
{
|
|
private:
|
|
PinConnectedPinIterator();
|
|
~PinConnectedPinIterator();
|
|
};
|
|
|
|
class Clock
|
|
{
|
|
private:
|
|
Clock();
|
|
~Clock();
|
|
};
|
|
|
|
class ClockIterator
|
|
{
|
|
private:
|
|
ClockIterator();
|
|
~ClockIterator();
|
|
};
|
|
|
|
class ClockEdge
|
|
{
|
|
private:
|
|
ClockEdge();
|
|
~ClockEdge();
|
|
};
|
|
|
|
class Vertex
|
|
{
|
|
private:
|
|
Vertex();
|
|
~Vertex();
|
|
};
|
|
|
|
class Edge
|
|
{
|
|
private:
|
|
Edge();
|
|
~Edge();
|
|
};
|
|
|
|
class VertexIterator
|
|
{
|
|
private:
|
|
VertexIterator();
|
|
~VertexIterator();
|
|
};
|
|
|
|
class VertexInEdgeIterator
|
|
{
|
|
private:
|
|
VertexInEdgeIterator();
|
|
~VertexInEdgeIterator();
|
|
};
|
|
|
|
class VertexOutEdgeIterator
|
|
{
|
|
private:
|
|
VertexOutEdgeIterator();
|
|
~VertexOutEdgeIterator();
|
|
};
|
|
|
|
class PathRef
|
|
{
|
|
private:
|
|
PathRef();
|
|
~PathRef();
|
|
};
|
|
|
|
class PathEnd
|
|
{
|
|
private:
|
|
PathEnd();
|
|
~PathEnd();
|
|
};
|
|
|
|
class MinPulseWidthCheck
|
|
{
|
|
private:
|
|
MinPulseWidthCheck();
|
|
~MinPulseWidthCheck();
|
|
};
|
|
|
|
class MinPulseWidthCheckSeq
|
|
{
|
|
private:
|
|
MinPulseWidthCheckSeq();
|
|
~MinPulseWidthCheckSeq();
|
|
};
|
|
|
|
class MinPulseWidthCheckSeqIterator
|
|
{
|
|
private:
|
|
MinPulseWidthCheckSeqIterator();
|
|
~MinPulseWidthCheckSeqIterator();
|
|
};
|
|
|
|
class VertexPathIterator
|
|
{
|
|
private:
|
|
VertexPathIterator();
|
|
~VertexPathIterator();
|
|
};
|
|
|
|
class SlowDrvrIterator
|
|
{
|
|
private:
|
|
SlowDrvrIterator();
|
|
~SlowDrvrIterator();
|
|
};
|
|
|
|
class ExceptionFrom
|
|
{
|
|
private:
|
|
ExceptionFrom();
|
|
~ExceptionFrom();
|
|
};
|
|
|
|
class ExceptionThru
|
|
{
|
|
private:
|
|
ExceptionThru();
|
|
~ExceptionThru();
|
|
};
|
|
|
|
class ExceptionTo
|
|
{
|
|
private:
|
|
ExceptionTo();
|
|
~ExceptionTo();
|
|
};
|
|
|
|
class OperatingConditions
|
|
{
|
|
private:
|
|
OperatingConditions();
|
|
~OperatingConditions();
|
|
};
|
|
|
|
class Corner
|
|
{
|
|
private:
|
|
Corner();
|
|
~Corner();
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// C++ functions visible as TCL functions.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
%inline %{
|
|
|
|
float float_inf = INF;
|
|
int group_count_max = PathGroup::group_count_max;
|
|
|
|
const char *
|
|
version()
|
|
{
|
|
return STA_VERSION;
|
|
}
|
|
|
|
const char *
|
|
git_sha1()
|
|
{
|
|
return STA_GIT_SHA1;
|
|
}
|
|
|
|
void
|
|
report_error(int id,
|
|
const char *msg)
|
|
{
|
|
Report *report = Sta::sta()->report();
|
|
report->error(id, "%s", msg);
|
|
}
|
|
|
|
void
|
|
report_file_error(int id,
|
|
const char *filename,
|
|
int line,
|
|
const char *msg)
|
|
{
|
|
Report *report = Sta::sta()->report();
|
|
report->error(id, filename, line, "%s", msg);
|
|
}
|
|
|
|
void
|
|
report_warn(int id,
|
|
const char *msg)
|
|
{
|
|
Report *report = Sta::sta()->report();
|
|
report->warn(id, "%s", msg);
|
|
}
|
|
|
|
void
|
|
report_file_warn(int id,
|
|
const char *filename,
|
|
int line,
|
|
const char *msg)
|
|
{
|
|
Report *report = Sta::sta()->report();
|
|
report->fileWarn(id, filename, line, "%s", msg);
|
|
}
|
|
|
|
void
|
|
report_line(const char *msg)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
if (sta)
|
|
sta->report()->reportLineString(msg);
|
|
else
|
|
// After sta::delete_all_memory souce -echo prints the cmd file line
|
|
printf("%s\n", msg);
|
|
}
|
|
|
|
void
|
|
fflush()
|
|
{
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
}
|
|
|
|
void
|
|
redirect_file_begin(const char *filename)
|
|
{
|
|
Sta::sta()->report()->redirectFileBegin(filename);
|
|
}
|
|
|
|
void
|
|
redirect_file_append_begin(const char *filename)
|
|
{
|
|
Sta::sta()->report()->redirectFileAppendBegin(filename);
|
|
}
|
|
|
|
void
|
|
redirect_file_end()
|
|
{
|
|
Sta::sta()->report()->redirectFileEnd();
|
|
}
|
|
|
|
void
|
|
redirect_string_begin()
|
|
{
|
|
Sta::sta()->report()->redirectStringBegin();
|
|
}
|
|
|
|
const char *
|
|
redirect_string_end()
|
|
{
|
|
return Sta::sta()->report()->redirectStringEnd();
|
|
}
|
|
|
|
void
|
|
log_begin_cmd(const char *filename)
|
|
{
|
|
Sta::sta()->report()->logBegin(filename);
|
|
}
|
|
|
|
void
|
|
log_end()
|
|
{
|
|
Sta::sta()->report()->logEnd();
|
|
}
|
|
|
|
void
|
|
set_debug(const char *what,
|
|
int level)
|
|
{
|
|
Sta::sta()->setDebugLevel(what, level);
|
|
}
|
|
|
|
bool
|
|
is_object(const char *obj)
|
|
{
|
|
// _hexaddress_p_type
|
|
const char *s = obj;
|
|
char ch = *s++;
|
|
if (ch != '_')
|
|
return false;
|
|
while (*s && isxdigit(*s))
|
|
s++;
|
|
if ((s - obj - 1) == sizeof(void*) * 2
|
|
&& *s && *s++ == '_'
|
|
&& *s && *s++ == 'p'
|
|
&& *s && *s++ == '_') {
|
|
while (*s && *s != ' ')
|
|
s++;
|
|
return *s == '\0';
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Assumes is_object is true.
|
|
const char *
|
|
object_type(const char *obj)
|
|
{
|
|
return &obj[1 + sizeof(void*) * 2 + 3];
|
|
}
|
|
|
|
bool
|
|
is_object_list(const char *list,
|
|
const char *type)
|
|
{
|
|
const char *s = list;
|
|
while (s) {
|
|
bool type_match;
|
|
const char *next;
|
|
objectListNext(s, type, type_match, next);
|
|
if (type_match)
|
|
s = next;
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
set_rise_fall_short_names(const char *rise_short_name,
|
|
const char *fall_short_name)
|
|
{
|
|
RiseFall::rise()->setShortName(rise_short_name);
|
|
RiseFall::fall()->setShortName(fall_short_name);
|
|
|
|
RiseFallBoth::rise()->setShortName(rise_short_name);
|
|
RiseFallBoth::fall()->setShortName(fall_short_name);
|
|
|
|
Transition::rise()->setName(rise_short_name);
|
|
Transition::fall()->setName(fall_short_name);
|
|
}
|
|
|
|
const char *
|
|
rise_short_name()
|
|
{
|
|
return RiseFall::rise()->shortName();
|
|
}
|
|
|
|
const char *
|
|
fall_short_name()
|
|
{
|
|
return RiseFall::fall()->shortName();
|
|
}
|
|
|
|
bool
|
|
pin_is_constrained(Pin *pin)
|
|
{
|
|
return Sta::sta()->sdc()->isConstrained(pin);
|
|
}
|
|
|
|
bool
|
|
instance_is_constrained(Instance *inst)
|
|
{
|
|
return Sta::sta()->sdc()->isConstrained(inst);
|
|
}
|
|
|
|
bool
|
|
net_is_constrained(Net *net)
|
|
{
|
|
return Sta::sta()->sdc()->isConstrained(net);
|
|
}
|
|
|
|
bool
|
|
clk_thru_tristate_enabled()
|
|
{
|
|
return Sta::sta()->clkThruTristateEnabled();
|
|
}
|
|
|
|
void
|
|
set_clk_thru_tristate_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setClkThruTristateEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
network_is_linked()
|
|
{
|
|
return Sta::sta()->cmdNetwork()->isLinked();
|
|
}
|
|
|
|
void
|
|
set_path_divider(char divider)
|
|
{
|
|
cmdNetwork()->setPathDivider(divider);
|
|
}
|
|
|
|
void
|
|
set_current_instance(Instance *inst)
|
|
{
|
|
Sta::sta()->setCurrentInstance(inst);
|
|
}
|
|
|
|
bool
|
|
read_liberty_cmd(char *filename,
|
|
Corner *corner,
|
|
const MinMaxAll *min_max,
|
|
bool infer_latches)
|
|
{
|
|
LibertyLibrary *lib = Sta::sta()->readLiberty(filename, corner, min_max,
|
|
infer_latches);
|
|
return (lib != nullptr);
|
|
}
|
|
|
|
bool
|
|
set_min_library_cmd(char *min_filename,
|
|
char *max_filename)
|
|
{
|
|
return Sta::sta()->setMinLibrary(min_filename, max_filename);
|
|
}
|
|
|
|
void
|
|
write_liberty_cmd(LibertyLibrary *library,
|
|
char *filename)
|
|
{
|
|
writeLiberty(library, filename, Sta::sta());
|
|
}
|
|
|
|
Library *
|
|
find_library(const char *name)
|
|
{
|
|
return cmdNetwork()->findLibrary(name);
|
|
}
|
|
|
|
LibraryIterator *
|
|
library_iterator()
|
|
{
|
|
return cmdNetwork()->libraryIterator();
|
|
}
|
|
|
|
LibertyLibrary *
|
|
find_liberty(const char *name)
|
|
{
|
|
return cmdNetwork()->findLiberty(name);
|
|
}
|
|
|
|
LibertyLibraryIterator *
|
|
liberty_library_iterator()
|
|
{
|
|
return cmdNetwork()->libertyLibraryIterator();
|
|
}
|
|
|
|
LibertyCell *
|
|
find_liberty_cell(const char *name)
|
|
{
|
|
return cmdNetwork()->findLibertyCell(name);
|
|
}
|
|
|
|
TmpCellSeq *
|
|
find_cells_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Network *network = cmdNetwork();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
TmpCellSeq *cells = new TmpCellSeq;
|
|
LibraryIterator *lib_iter = network->libraryIterator();
|
|
while (lib_iter->hasNext()) {
|
|
Library *lib = lib_iter->next();
|
|
network->findCellsMatching(lib, &matcher, cells);
|
|
}
|
|
delete lib_iter;
|
|
return cells;
|
|
}
|
|
|
|
LibertyCellSeq *
|
|
find_library_buffers(LibertyLibrary *library)
|
|
{
|
|
return library->buffers();
|
|
}
|
|
|
|
void
|
|
make_equiv_cells(LibertyLibrary *lib)
|
|
{
|
|
LibertyLibrarySeq libs;
|
|
libs.push_back(lib);
|
|
Sta::sta()->makeEquivCells(&libs, nullptr);
|
|
}
|
|
|
|
LibertyCellSeq *
|
|
find_equiv_cells(LibertyCell *cell)
|
|
{
|
|
return Sta::sta()->equivCells(cell);
|
|
}
|
|
|
|
bool
|
|
equiv_cells(LibertyCell *cell1,
|
|
LibertyCell *cell2)
|
|
{
|
|
return sta::equivCells(cell1, cell2);
|
|
}
|
|
|
|
bool
|
|
equiv_cell_ports(LibertyCell *cell1,
|
|
LibertyCell *cell2)
|
|
{
|
|
return equivCellPorts(cell1, cell2);
|
|
}
|
|
|
|
bool
|
|
equiv_cell_timing_arcs(LibertyCell *cell1,
|
|
LibertyCell *cell2)
|
|
{
|
|
return equivCellTimingArcSets(cell1, cell2);
|
|
}
|
|
|
|
void
|
|
set_cmd_namespace_cmd(const char *namespc)
|
|
{
|
|
if (stringEq(namespc, "sdc"))
|
|
Sta::sta()->setCmdNamespace(CmdNamespace::sdc);
|
|
else if (stringEq(namespc, "sta"))
|
|
Sta::sta()->setCmdNamespace(CmdNamespace::sta);
|
|
else
|
|
criticalError(269, "unknown namespace");
|
|
}
|
|
|
|
bool
|
|
link_design_cmd(const char *top_cell_name)
|
|
{
|
|
return Sta::sta()->linkDesign(top_cell_name);
|
|
}
|
|
|
|
bool
|
|
link_make_black_boxes()
|
|
{
|
|
return Sta::sta()->linkMakeBlackBoxes();
|
|
}
|
|
|
|
void
|
|
set_link_make_black_boxes(bool make)
|
|
{
|
|
Sta::sta()->setLinkMakeBlackBoxes(make);
|
|
}
|
|
|
|
Instance *
|
|
top_instance()
|
|
{
|
|
return cmdLinkedNetwork()->topInstance();
|
|
}
|
|
|
|
const char *
|
|
liberty_port_direction(const LibertyPort *port)
|
|
{
|
|
return port->direction()->name();
|
|
}
|
|
|
|
const char *
|
|
port_direction(const Port *port)
|
|
{
|
|
return cmdLinkedNetwork()->direction(port)->name();
|
|
}
|
|
|
|
const char *
|
|
pin_direction(const Pin *pin)
|
|
{
|
|
return cmdLinkedNetwork()->direction(pin)->name();
|
|
}
|
|
|
|
TmpPortSeq *
|
|
find_ports_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
Cell *top_cell = network->cell(network->topInstance());
|
|
PortSeq ports1;
|
|
network->findPortsMatching(top_cell, &matcher, &ports1);
|
|
// Expand bus/bundle ports.
|
|
TmpPortSeq *ports = new TmpPortSeq;
|
|
PortSeq::Iterator port_iter(ports1);
|
|
while (port_iter.hasNext()) {
|
|
Port *port = port_iter.next();
|
|
if (network->isBus(port)
|
|
|| network->isBundle(port)) {
|
|
PortMemberIterator *member_iter = network->memberIterator(port);
|
|
while (member_iter->hasNext()) {
|
|
Port *member = member_iter->next();
|
|
ports->push_back(member);
|
|
}
|
|
delete member_iter;
|
|
}
|
|
else
|
|
ports->push_back(port);
|
|
}
|
|
return ports;
|
|
}
|
|
|
|
TmpPinSeq *
|
|
find_port_pins_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
PortSeq ports;
|
|
Instance *top_inst = network->topInstance();
|
|
Cell *top_cell = network->cell(top_inst);
|
|
network->findPortsMatching(top_cell, &matcher, &ports);
|
|
TmpPinSeq *pins = new TmpPinSeq;
|
|
PortSeq::Iterator port_iter(ports);
|
|
while (port_iter.hasNext()) {
|
|
Port *port = port_iter.next();
|
|
if (network->isBus(port)
|
|
|| network->isBundle(port)) {
|
|
PortMemberIterator *member_iter = network->memberIterator(port);
|
|
while (member_iter->hasNext()) {
|
|
Port *member = member_iter->next();
|
|
Pin *pin = network->findPin(top_inst, member);
|
|
if (pin)
|
|
pins->push_back(pin);
|
|
}
|
|
delete member_iter;
|
|
}
|
|
else {
|
|
Pin *pin = network->findPin(top_inst, port);
|
|
if (pin)
|
|
pins->push_back(pin);
|
|
}
|
|
}
|
|
return pins;
|
|
}
|
|
|
|
Pin *
|
|
find_pin(const char *path_name)
|
|
{
|
|
return cmdLinkedNetwork()->findPin(path_name);
|
|
}
|
|
|
|
TmpPinSeq *
|
|
find_pins_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Network *network = cmdLinkedNetwork();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
Instance *current_instance = sta->currentInstance();
|
|
TmpPinSeq *pins = new TmpPinSeq;
|
|
network->findPinsMatching(current_instance, &matcher, pins);
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSeq *
|
|
find_pins_hier_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Network *network = cmdLinkedNetwork();
|
|
Instance *current_instance = sta->currentInstance();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
TmpPinSeq *pins = new TmpPinSeq;
|
|
network->findPinsHierMatching(current_instance, &matcher, pins);
|
|
return pins;
|
|
}
|
|
|
|
Instance *
|
|
find_instance(char *path_name)
|
|
{
|
|
return cmdLinkedNetwork()->findInstance(path_name);
|
|
}
|
|
|
|
TmpInstanceSeq *
|
|
network_leaf_instances()
|
|
{
|
|
InstanceSeq *insts = new InstanceSeq;
|
|
LeafInstanceIterator *iter = cmdLinkedNetwork()->leafInstanceIterator();
|
|
while (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
insts->push_back(inst);
|
|
}
|
|
delete iter;
|
|
return insts;
|
|
}
|
|
|
|
TmpInstanceSeq *
|
|
find_instances_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Instance *current_instance = sta->currentInstance();
|
|
PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp());
|
|
TmpInstanceSeq *insts = new InstanceSeq;
|
|
cmdLinkedNetwork()->findInstancesMatching(current_instance, &matcher, insts);
|
|
return insts;
|
|
}
|
|
|
|
TmpInstanceSeq *
|
|
find_instances_hier_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Network *network = cmdLinkedNetwork();
|
|
Instance *current_instance = sta->currentInstance();
|
|
PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp());
|
|
TmpInstanceSeq *insts = new InstanceSeq;
|
|
network->findInstancesHierMatching(current_instance, &matcher, insts);
|
|
return insts;
|
|
}
|
|
|
|
TmpInstanceSet *
|
|
find_register_instances(ClockSet *clks,
|
|
const RiseFallBoth *clk_tr,
|
|
bool edge_triggered,
|
|
bool latches)
|
|
{
|
|
cmdLinkedNetwork();
|
|
InstanceSet *insts = Sta::sta()->findRegisterInstances(clks, clk_tr,
|
|
edge_triggered,
|
|
latches);
|
|
delete clks;
|
|
return insts;
|
|
}
|
|
|
|
TmpPinSet *
|
|
find_register_data_pins(ClockSet *clks,
|
|
const RiseFallBoth *clk_tr,
|
|
bool edge_triggered,
|
|
bool latches)
|
|
{
|
|
cmdLinkedNetwork();
|
|
PinSet *pins = Sta::sta()->findRegisterDataPins(clks, clk_tr,
|
|
edge_triggered, latches);
|
|
delete clks;
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSet *
|
|
find_register_clk_pins(ClockSet *clks,
|
|
const RiseFallBoth *clk_tr,
|
|
bool edge_triggered,
|
|
bool latches)
|
|
{
|
|
cmdLinkedNetwork();
|
|
PinSet *pins = Sta::sta()->findRegisterClkPins(clks, clk_tr,
|
|
edge_triggered, latches);
|
|
delete clks;
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSet *
|
|
find_register_async_pins(ClockSet *clks,
|
|
const RiseFallBoth *clk_tr,
|
|
bool edge_triggered,
|
|
bool latches)
|
|
{
|
|
cmdLinkedNetwork();
|
|
PinSet *pins = Sta::sta()->findRegisterAsyncPins(clks, clk_tr,
|
|
edge_triggered, latches);
|
|
delete clks;
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSet *
|
|
find_register_output_pins(ClockSet *clks,
|
|
const RiseFallBoth *clk_tr,
|
|
bool edge_triggered,
|
|
bool latches)
|
|
{
|
|
cmdLinkedNetwork();
|
|
PinSet *pins = Sta::sta()->findRegisterOutputPins(clks, clk_tr,
|
|
edge_triggered, latches);
|
|
delete clks;
|
|
return pins;
|
|
}
|
|
|
|
Net *
|
|
find_net(char *path_name)
|
|
{
|
|
return cmdLinkedNetwork()->findNet(path_name);
|
|
}
|
|
|
|
NetSeq *
|
|
find_nets_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
Instance *current_instance = Sta::sta()->currentInstance();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
NetSeq *nets = new NetSeq;
|
|
network->findNetsMatching(current_instance, &matcher, nets);
|
|
return nets;
|
|
}
|
|
|
|
NetSeq *
|
|
find_nets_hier_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
Instance *current_instance = Sta::sta()->currentInstance();
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
NetSeq *nets = new NetSeq;
|
|
network->findNetsHierMatching(current_instance, &matcher, nets);
|
|
return nets;
|
|
}
|
|
|
|
TmpPortSeq *
|
|
filter_ports(const char *property,
|
|
const char *op,
|
|
const char *pattern,
|
|
PortSeq *ports)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpPortSeq *filtered_ports = new TmpPortSeq;
|
|
PortSeq::Iterator port_iter(ports);
|
|
bool exact_match = stringEq(op, "==");
|
|
while (port_iter.hasNext()) {
|
|
Port *port = port_iter.next();
|
|
PropertyValue value(getProperty(port, property, sta));
|
|
const char *prop = value.stringValue();
|
|
if (prop &&
|
|
((exact_match && stringEq(prop, pattern))
|
|
|| (!exact_match && patternMatch(pattern, prop))))
|
|
filtered_ports->push_back(port);
|
|
}
|
|
delete ports;
|
|
return filtered_ports;
|
|
}
|
|
|
|
TmpInstanceSeq *
|
|
filter_insts(const char *property,
|
|
const char *op,
|
|
const char *pattern,
|
|
InstanceSeq *insts)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
cmdLinkedNetwork();
|
|
TmpInstanceSeq *filtered_insts = new TmpInstanceSeq;
|
|
TmpInstanceSeq::Iterator inst_iter(insts);
|
|
bool exact_match = stringEq(op, "==");
|
|
while (inst_iter.hasNext()) {
|
|
Instance *inst = inst_iter.next();
|
|
PropertyValue value(getProperty(inst, property, sta));
|
|
const char *prop = value.stringValue();
|
|
if (prop &&
|
|
((exact_match && stringEq(prop, pattern))
|
|
|| (!exact_match && patternMatch(pattern, prop))))
|
|
filtered_insts->push_back(inst);
|
|
}
|
|
delete insts;
|
|
return filtered_insts;
|
|
}
|
|
|
|
PinSeq *
|
|
filter_pins(const char *property,
|
|
const char *op,
|
|
const char *pattern,
|
|
PinSeq *pins)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
PinSeq *filtered_pins = new PinSeq;
|
|
PinSeq::Iterator pin_iter(pins);
|
|
bool exact_match = stringEq(op, "==");
|
|
while (pin_iter.hasNext()) {
|
|
Pin *pin = pin_iter.next();
|
|
PropertyValue value(getProperty(pin, property, sta));
|
|
const char *prop = value.stringValue();
|
|
if (prop &&
|
|
((exact_match && stringEq(prop, pattern))
|
|
|| (!exact_match && patternMatch(pattern, prop))))
|
|
filtered_pins->push_back(pin);
|
|
}
|
|
delete pins;
|
|
return filtered_pins;
|
|
}
|
|
|
|
PropertyValue
|
|
pin_property(const Pin *pin,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(pin, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
instance_property(const Instance *inst,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(inst, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
net_property(const Net *net,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(net, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
port_property(const Port *port,
|
|
const char *property)
|
|
{
|
|
return getProperty(port, property, Sta::sta());
|
|
}
|
|
|
|
|
|
PropertyValue
|
|
liberty_cell_property(const LibertyCell *cell,
|
|
const char *property)
|
|
{
|
|
return getProperty(cell, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
cell_property(const Cell *cell,
|
|
const char *property)
|
|
{
|
|
return getProperty(cell, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
liberty_port_property(const LibertyPort *port,
|
|
const char *property)
|
|
{
|
|
return getProperty(port, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
library_property(const Library *lib,
|
|
const char *property)
|
|
{
|
|
return getProperty(lib, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
liberty_library_property(const LibertyLibrary *lib,
|
|
const char *property)
|
|
{
|
|
return getProperty(lib, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
edge_property(Edge *edge,
|
|
const char *property)
|
|
{
|
|
cmdGraph();
|
|
return getProperty(edge, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
clock_property(Clock *clk,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(clk, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
path_end_property(PathEnd *end,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(end, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
path_ref_property(PathRef *path,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(path, property, Sta::sta());
|
|
}
|
|
|
|
PropertyValue
|
|
timing_arc_set_property(TimingArcSet *arc_set,
|
|
const char *property)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return getProperty(arc_set, property, Sta::sta());
|
|
}
|
|
|
|
LeafInstanceIterator *
|
|
leaf_instance_iterator()
|
|
{
|
|
return cmdLinkedNetwork()->leafInstanceIterator();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
define_corners_cmd(StringSet *corner_names)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
sta->makeCorners(corner_names);
|
|
delete corner_names;
|
|
}
|
|
|
|
Corner *
|
|
cmd_corner()
|
|
{
|
|
return Sta::sta()->cmdCorner();
|
|
}
|
|
|
|
void
|
|
set_cmd_corner(Corner *corner)
|
|
{
|
|
Sta::sta()->setCmdCorner(corner);
|
|
}
|
|
|
|
Corner *
|
|
find_corner(const char *corner_name)
|
|
{
|
|
return Sta::sta()->findCorner(corner_name);
|
|
}
|
|
|
|
Corners *
|
|
corners()
|
|
{
|
|
return Sta::sta()->corners();
|
|
}
|
|
|
|
bool
|
|
multi_corner()
|
|
{
|
|
return Sta::sta()->multiCorner();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
set_analysis_type_cmd(const char *analysis_type)
|
|
{
|
|
AnalysisType type;
|
|
if (stringEq(analysis_type, "single"))
|
|
type = AnalysisType::single;
|
|
else if (stringEq(analysis_type, "bc_wc"))
|
|
type = AnalysisType::bc_wc;
|
|
else if (stringEq(analysis_type, "on_chip_variation"))
|
|
type = AnalysisType::ocv;
|
|
else {
|
|
criticalError(270, "unknown analysis type");
|
|
type = AnalysisType::single;
|
|
}
|
|
Sta::sta()->setAnalysisType(type);
|
|
}
|
|
|
|
OperatingConditions *
|
|
operating_conditions(const MinMax *min_max)
|
|
{
|
|
return Sta::sta()->operatingConditions(min_max);
|
|
}
|
|
|
|
void
|
|
set_operating_conditions_cmd(OperatingConditions *op_cond,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
Sta::sta()->setOperatingConditions(op_cond, min_max);
|
|
}
|
|
|
|
EdgeSeq *
|
|
filter_timing_arcs(const char *property,
|
|
const char *op,
|
|
const char *pattern,
|
|
EdgeSeq *edges)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
EdgeSeq *filtered_edges = new EdgeSeq;
|
|
EdgeSeq::Iterator edge_iter(edges);
|
|
bool exact_match = stringEq(op, "==");
|
|
while (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
PropertyValue value(getProperty(edge, property, sta));
|
|
const char *prop = value.stringValue();
|
|
if (prop &&
|
|
((exact_match && stringEq(prop, pattern))
|
|
|| (!exact_match && patternMatch(pattern, prop))))
|
|
filtered_edges->push_back(edge);
|
|
}
|
|
delete edges;
|
|
return filtered_edges;
|
|
}
|
|
|
|
const char *
|
|
operating_condition_analysis_type()
|
|
{
|
|
switch (Sta::sta()->sdc()->analysisType()){
|
|
case AnalysisType::single:
|
|
return "single";
|
|
case AnalysisType::bc_wc:
|
|
return "bc_wc";
|
|
case AnalysisType::ocv:
|
|
return "on_chip_variation";
|
|
}
|
|
// Prevent warnings from lame compilers.
|
|
return "?";
|
|
}
|
|
|
|
void
|
|
set_instance_pvt(Instance *inst,
|
|
const MinMaxAll *min_max,
|
|
float process,
|
|
float voltage,
|
|
float temperature)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Pvt *pvt = new Pvt(process, voltage, temperature);
|
|
Sta::sta()->setPvt(inst, min_max, pvt);
|
|
}
|
|
|
|
float
|
|
port_ext_pin_cap(Port *port,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
int fanout;
|
|
Sta::sta()->portExtCaps(port, min_max, pin_cap, wire_cap, fanout);
|
|
return pin_cap;
|
|
}
|
|
|
|
void
|
|
set_port_pin_cap(Port *port,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
float cap)
|
|
{
|
|
Sta::sta()->setPortExtPinCap(port, rf, min_max, cap);
|
|
}
|
|
|
|
float
|
|
port_ext_wire_cap(Port *port,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
int fanout;
|
|
Sta::sta()->portExtCaps(port, min_max, pin_cap, wire_cap, fanout);
|
|
return wire_cap;
|
|
}
|
|
|
|
void
|
|
set_port_wire_cap(Port *port,
|
|
bool subtract_pin_cap,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
float cap)
|
|
{
|
|
Sta::sta()->setPortExtWireCap(port, subtract_pin_cap, rf, min_max, cap);
|
|
}
|
|
|
|
void
|
|
set_port_ext_fanout_cmd(Port *port,
|
|
int fanout,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
Sta::sta()->setPortExtFanout(port, fanout, min_max);
|
|
}
|
|
|
|
float
|
|
port_ext_fanout(Port *port,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
int fanout;
|
|
Sta::sta()->portExtCaps(port, min_max, pin_cap, wire_cap, fanout);
|
|
return fanout;
|
|
}
|
|
|
|
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, corner, min_max, cap);
|
|
}
|
|
|
|
void
|
|
set_wire_load_mode_cmd(const char *mode_name)
|
|
{
|
|
WireloadMode mode = stringWireloadMode(mode_name);
|
|
if (mode == WireloadMode::unknown)
|
|
criticalError(271, "unknown wire load mode");
|
|
else
|
|
Sta::sta()->setWireloadMode(mode);
|
|
}
|
|
|
|
void
|
|
set_net_resistance(Net *net,
|
|
const MinMaxAll *min_max,
|
|
float res)
|
|
{
|
|
Sta::sta()->setResistance(net, min_max, res);
|
|
}
|
|
|
|
void
|
|
set_wire_load_cmd(Wireload *wireload,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
Sta::sta()->setWireload(wireload, min_max);
|
|
}
|
|
|
|
void
|
|
set_wire_load_selection_group_cmd(WireloadSelection *selection,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
Sta::sta()->setWireloadSelection(selection, min_max);
|
|
}
|
|
|
|
void
|
|
make_clock(const char *name,
|
|
PinSet *pins,
|
|
bool add_to_pins,
|
|
float period,
|
|
FloatSeq *waveform,
|
|
char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->makeClock(name, pins, add_to_pins, period, waveform, comment);
|
|
}
|
|
|
|
void
|
|
make_generated_clock(const char *name,
|
|
PinSet *pins,
|
|
bool add_to_pins,
|
|
Pin *src_pin,
|
|
Clock *master_clk,
|
|
Pin *pll_out,
|
|
Pin *pll_fdbk,
|
|
int divide_by,
|
|
int multiply_by,
|
|
float duty_cycle,
|
|
bool invert,
|
|
bool combinational,
|
|
IntSeq *edges,
|
|
FloatSeq *edge_shifts,
|
|
char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->makeGeneratedClock(name, pins, add_to_pins,
|
|
src_pin, master_clk, pll_out, pll_fdbk,
|
|
divide_by, multiply_by, duty_cycle, invert,
|
|
combinational, edges, edge_shifts,
|
|
comment);
|
|
}
|
|
|
|
void
|
|
remove_clock_cmd(Clock *clk)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClock(clk);
|
|
}
|
|
|
|
void
|
|
set_propagated_clock_cmd(Clock *clk)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setPropagatedClock(clk);
|
|
}
|
|
|
|
void
|
|
set_propagated_clock_pin_cmd(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setPropagatedClock(pin);
|
|
}
|
|
|
|
void
|
|
unset_propagated_clock_cmd(Clock *clk)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removePropagatedClock(clk);
|
|
}
|
|
|
|
void
|
|
unset_propagated_clock_pin_cmd(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removePropagatedClock(pin);
|
|
}
|
|
|
|
void
|
|
set_clock_slew_cmd(Clock *clk,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
float slew)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockSlew(clk, rf, min_max, slew);
|
|
}
|
|
|
|
void
|
|
unset_clock_slew_cmd(Clock *clk)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockSlew(clk);
|
|
}
|
|
|
|
void
|
|
set_clock_latency_cmd(Clock *clk,
|
|
Pin *pin,
|
|
const RiseFallBoth *rf,
|
|
MinMaxAll *min_max, float delay)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockLatency(clk, pin, rf, min_max, delay);
|
|
}
|
|
|
|
void
|
|
set_clock_insertion_cmd(Clock *clk,
|
|
Pin *pin,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
const EarlyLateAll *early_late,
|
|
float delay)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockInsertion(clk, pin, rf, min_max, early_late, delay);
|
|
}
|
|
|
|
void
|
|
unset_clock_latency_cmd(Clock *clk,
|
|
Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockLatency(clk, pin);
|
|
}
|
|
|
|
void
|
|
unset_clock_insertion_cmd(Clock *clk,
|
|
Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockInsertion(clk, pin);
|
|
}
|
|
|
|
void
|
|
set_clock_uncertainty_clk(Clock *clk,
|
|
const SetupHoldAll *setup_hold,
|
|
float uncertainty)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockUncertainty(clk, setup_hold, uncertainty);
|
|
}
|
|
|
|
void
|
|
unset_clock_uncertainty_clk(Clock *clk,
|
|
const SetupHoldAll *setup_hold)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockUncertainty(clk, setup_hold);
|
|
}
|
|
|
|
void
|
|
set_clock_uncertainty_pin(Pin *pin,
|
|
const MinMaxAll *min_max,
|
|
float uncertainty)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockUncertainty(pin, min_max, uncertainty);
|
|
}
|
|
|
|
void
|
|
unset_clock_uncertainty_pin(Pin *pin,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockUncertainty(pin, min_max);
|
|
}
|
|
|
|
void
|
|
set_inter_clock_uncertainty(Clock *from_clk,
|
|
const RiseFallBoth *from_tr,
|
|
Clock *to_clk,
|
|
const RiseFallBoth *to_tr,
|
|
const MinMaxAll *min_max,
|
|
float uncertainty)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setClockUncertainty(from_clk, from_tr, to_clk, to_tr, min_max,
|
|
uncertainty);
|
|
}
|
|
|
|
void
|
|
unset_inter_clock_uncertainty(Clock *from_clk,
|
|
const RiseFallBoth *from_tr,
|
|
Clock *to_clk,
|
|
const RiseFallBoth *to_tr,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeClockUncertainty(from_clk, from_tr, to_clk, to_tr, min_max);
|
|
}
|
|
|
|
void
|
|
set_clock_gating_check_cmd(const RiseFallBoth *rf,
|
|
const SetupHold *setup_hold,
|
|
float margin)
|
|
{
|
|
Sta::sta()->setClockGatingCheck(rf, setup_hold, margin);
|
|
}
|
|
|
|
void
|
|
set_clock_gating_check_clk_cmd(Clock *clk,
|
|
const RiseFallBoth *rf,
|
|
const SetupHold *setup_hold,
|
|
float margin)
|
|
{
|
|
Sta::sta()->setClockGatingCheck(clk, rf, setup_hold, margin);
|
|
}
|
|
|
|
void
|
|
set_clock_gating_check_pin_cmd(Pin *pin,
|
|
const RiseFallBoth *rf,
|
|
const SetupHold *setup_hold,
|
|
float margin,
|
|
LogicValue active_value)
|
|
{
|
|
Sta::sta()->setClockGatingCheck(pin, rf, setup_hold, margin, active_value);
|
|
}
|
|
|
|
void
|
|
set_clock_gating_check_instance_cmd(Instance *inst,
|
|
const RiseFallBoth *rf,
|
|
const SetupHold *setup_hold,
|
|
float margin,
|
|
LogicValue active_value)
|
|
{
|
|
Sta::sta()->setClockGatingCheck(inst, rf, setup_hold, margin, active_value);
|
|
}
|
|
|
|
void
|
|
set_data_check_cmd(Pin *from,
|
|
const RiseFallBoth *from_rf,
|
|
Pin *to,
|
|
const RiseFallBoth *to_rf,
|
|
Clock *clk,
|
|
const SetupHoldAll *setup_hold,
|
|
float margin)
|
|
{
|
|
Sta::sta()->setDataCheck(from, from_rf, to, to_rf, clk, setup_hold, margin);
|
|
}
|
|
|
|
void
|
|
unset_data_check_cmd(Pin *from,
|
|
const RiseFallBoth *from_tr,
|
|
Pin *to,
|
|
const RiseFallBoth *to_tr,
|
|
Clock *clk,
|
|
const SetupHoldAll *setup_hold)
|
|
{
|
|
Sta::sta()->removeDataCheck(from, from_tr, to, to_tr, clk, setup_hold);
|
|
}
|
|
|
|
void
|
|
set_input_delay_cmd(Pin *pin,
|
|
RiseFallBoth *rf,
|
|
Clock *clk,
|
|
RiseFall *clk_rf,
|
|
Pin *ref_pin,
|
|
bool source_latency_included,
|
|
bool network_latency_included,
|
|
MinMaxAll *min_max,
|
|
bool add,
|
|
float delay)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setInputDelay(pin, rf, clk, clk_rf, ref_pin,
|
|
source_latency_included, network_latency_included,
|
|
min_max, add, delay);
|
|
}
|
|
|
|
void
|
|
unset_input_delay_cmd(Pin *pin,
|
|
RiseFallBoth *rf,
|
|
Clock *clk,
|
|
RiseFall *clk_rf,
|
|
MinMaxAll *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeInputDelay(pin, rf, clk, clk_rf, min_max);
|
|
}
|
|
|
|
void
|
|
set_output_delay_cmd(Pin *pin,
|
|
const RiseFallBoth *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf,
|
|
Pin *ref_pin,
|
|
bool source_latency_included,
|
|
bool network_latency_included,
|
|
const MinMaxAll *min_max,
|
|
bool add,
|
|
float delay)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setOutputDelay(pin, rf, clk, clk_rf, ref_pin,
|
|
source_latency_included, network_latency_included,
|
|
min_max, add, delay);
|
|
}
|
|
|
|
void
|
|
unset_output_delay_cmd(Pin *pin,
|
|
RiseFallBoth *rf,
|
|
Clock *clk,
|
|
RiseFall *clk_rf,
|
|
MinMaxAll *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeOutputDelay(pin, rf, clk, clk_rf, min_max);
|
|
}
|
|
|
|
void
|
|
disable_cell(LibertyCell *cell,
|
|
LibertyPort *from,
|
|
LibertyPort *to)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(cell, from, to);
|
|
}
|
|
|
|
void
|
|
unset_disable_cell(LibertyCell *cell,
|
|
LibertyPort *from,
|
|
LibertyPort *to)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(cell, from, to);
|
|
}
|
|
|
|
void
|
|
disable_lib_port(LibertyPort *port)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(port);
|
|
}
|
|
|
|
void
|
|
unset_disable_lib_port(LibertyPort *port)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(port);
|
|
}
|
|
|
|
void
|
|
disable_port(Port *port)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(port);
|
|
}
|
|
|
|
void
|
|
unset_disable_port(Port *port)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(port);
|
|
}
|
|
|
|
void
|
|
disable_instance(Instance *instance,
|
|
LibertyPort *from,
|
|
LibertyPort *to)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(instance, from, to);
|
|
}
|
|
|
|
void
|
|
unset_disable_instance(Instance *instance,
|
|
LibertyPort *from,
|
|
LibertyPort *to)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(instance, from, to);
|
|
}
|
|
|
|
void
|
|
disable_pin(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(pin);
|
|
}
|
|
|
|
void
|
|
unset_disable_pin(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(pin);
|
|
}
|
|
|
|
void
|
|
disable_edge(Edge *edge)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(edge);
|
|
}
|
|
|
|
void
|
|
unset_disable_edge(Edge *edge)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(edge);
|
|
}
|
|
|
|
void
|
|
disable_timing_arc_set(TimingArcSet *arc_set)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disable(arc_set);
|
|
}
|
|
|
|
void
|
|
unset_disable_timing_arc_set(TimingArcSet *arc_set)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisable(arc_set);
|
|
}
|
|
|
|
void
|
|
disable_clock_gating_check_inst(Instance *inst)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disableClockGatingCheck(inst);
|
|
}
|
|
|
|
void
|
|
disable_clock_gating_check_pin(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->disableClockGatingCheck(pin);
|
|
}
|
|
|
|
void
|
|
unset_disable_clock_gating_check_inst(Instance *inst)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisableClockGatingCheck(inst);
|
|
}
|
|
|
|
void
|
|
unset_disable_clock_gating_check_pin(Pin *pin)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->removeDisableClockGatingCheck(pin);
|
|
}
|
|
|
|
void
|
|
make_false_path(ExceptionFrom *from,
|
|
ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
const MinMaxAll *min_max,
|
|
const char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->makeFalsePath(from, thrus, to, min_max, comment);
|
|
}
|
|
|
|
void
|
|
make_multicycle_path(ExceptionFrom *from,
|
|
ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
const MinMaxAll *min_max,
|
|
bool use_end_clk,
|
|
int path_multiplier,
|
|
const char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->makeMulticyclePath(from, thrus, to, min_max, use_end_clk,
|
|
path_multiplier, comment);
|
|
}
|
|
|
|
void
|
|
make_path_delay(ExceptionFrom *from,
|
|
ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
const MinMax *min_max,
|
|
bool ignore_clk_latency,
|
|
float delay,
|
|
const char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->makePathDelay(from, thrus, to, min_max,
|
|
ignore_clk_latency, delay, comment);
|
|
}
|
|
|
|
void
|
|
reset_path_cmd(ExceptionFrom *
|
|
from, ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->resetPath(from, thrus, to, min_max);
|
|
// from/to and thru are owned and deleted by the caller.
|
|
// ExceptionThruSeq thrus arg is made by TclListSeqExceptionThru
|
|
// in the swig converter so it is deleted here.
|
|
delete thrus;
|
|
}
|
|
|
|
void
|
|
make_group_path(const char *name,
|
|
bool is_default,
|
|
ExceptionFrom *from,
|
|
ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
const char *comment)
|
|
{
|
|
cmdLinkedNetwork();
|
|
if (name[0] == '\0')
|
|
name = nullptr;
|
|
Sta::sta()->makeGroupPath(name, is_default, from, thrus, to, comment);
|
|
}
|
|
|
|
bool
|
|
is_path_group_name(const char *name)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->isGroupPathName(name);
|
|
}
|
|
|
|
ExceptionFrom *
|
|
make_exception_from(PinSet *from_pins,
|
|
ClockSet *from_clks,
|
|
InstanceSet *from_insts,
|
|
const RiseFallBoth *from_tr)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->makeExceptionFrom(from_pins, from_clks, from_insts,
|
|
from_tr);
|
|
}
|
|
|
|
void
|
|
delete_exception_from(ExceptionFrom *from)
|
|
{
|
|
Sta::sta()->deleteExceptionFrom(from);
|
|
}
|
|
|
|
void
|
|
check_exception_from_pins(ExceptionFrom *from,
|
|
const char *file,
|
|
int line)
|
|
{
|
|
Sta::sta()->checkExceptionFromPins(from, file, line);
|
|
}
|
|
|
|
ExceptionThru *
|
|
make_exception_thru(PinSet *pins,
|
|
NetSet *nets,
|
|
InstanceSet *insts,
|
|
const RiseFallBoth *rf)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->makeExceptionThru(pins, nets, insts, rf);
|
|
}
|
|
|
|
void
|
|
delete_exception_thru(ExceptionThru *thru)
|
|
{
|
|
Sta::sta()->deleteExceptionThru(thru);
|
|
}
|
|
|
|
ExceptionTo *
|
|
make_exception_to(PinSet *to_pins,
|
|
ClockSet *to_clks,
|
|
InstanceSet *to_insts,
|
|
const RiseFallBoth *rf,
|
|
RiseFallBoth *end_rf)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->makeExceptionTo(to_pins, to_clks, to_insts, rf, end_rf);
|
|
}
|
|
|
|
void
|
|
delete_exception_to(ExceptionTo *to)
|
|
{
|
|
Sta::sta()->deleteExceptionTo(to);
|
|
}
|
|
|
|
void
|
|
check_exception_to_pins(ExceptionTo *to,
|
|
const char *file,
|
|
int line)
|
|
{
|
|
Sta::sta()->checkExceptionToPins(to, file, line);
|
|
}
|
|
|
|
void
|
|
set_input_slew_cmd(Port *port,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
float slew)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setInputSlew(port, rf, min_max, slew);
|
|
}
|
|
|
|
void
|
|
set_drive_cell_cmd(LibertyLibrary *library,
|
|
LibertyCell *cell,
|
|
Port *port,
|
|
LibertyPort *from_port,
|
|
float from_slew_rise,
|
|
float from_slew_fall,
|
|
LibertyPort *to_port,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max)
|
|
{
|
|
float from_slews[RiseFall::index_count];
|
|
from_slews[RiseFall::riseIndex()] = from_slew_rise;
|
|
from_slews[RiseFall::fallIndex()] = from_slew_fall;
|
|
Sta::sta()->setDriveCell(library, cell, port, from_port, from_slews,
|
|
to_port, rf, min_max);
|
|
}
|
|
|
|
void
|
|
set_drive_resistance_cmd(Port *port,
|
|
const RiseFallBoth *rf,
|
|
const MinMaxAll *min_max,
|
|
float res)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setDriveResistance(port, rf, min_max, res);
|
|
}
|
|
|
|
void
|
|
set_slew_limit_clk(Clock *clk,
|
|
const RiseFallBoth *rf,
|
|
PathClkOrData clk_data,
|
|
const MinMax *min_max,
|
|
float slew)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setSlewLimit(clk, rf, clk_data, min_max, slew);
|
|
}
|
|
|
|
void
|
|
set_slew_limit_port(Port *port,
|
|
const MinMax *min_max,
|
|
float slew)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setSlewLimit(port, min_max, slew);
|
|
}
|
|
|
|
void
|
|
set_slew_limit_cell(Cell *cell,
|
|
const MinMax *min_max,
|
|
float slew)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->setSlewLimit(cell, min_max, slew);
|
|
}
|
|
|
|
void
|
|
set_port_capacitance_limit(Port *port,
|
|
const MinMax *min_max,
|
|
float cap)
|
|
{
|
|
Sta::sta()->setCapacitanceLimit(port, min_max, cap);
|
|
}
|
|
|
|
void
|
|
set_pin_capacitance_limit(Pin *pin,
|
|
const MinMax *min_max,
|
|
float cap)
|
|
{
|
|
Sta::sta()->setCapacitanceLimit(pin, min_max, cap);
|
|
}
|
|
|
|
void
|
|
set_cell_capacitance_limit(Cell *cell,
|
|
const MinMax *min_max,
|
|
float cap)
|
|
{
|
|
Sta::sta()->setCapacitanceLimit(cell, min_max, cap);
|
|
}
|
|
|
|
void
|
|
set_latch_borrow_limit_pin(Pin *pin,
|
|
float limit)
|
|
{
|
|
Sta::sta()->setLatchBorrowLimit(pin, limit);
|
|
}
|
|
|
|
void
|
|
set_latch_borrow_limit_inst(Instance *inst,
|
|
float limit)
|
|
{
|
|
Sta::sta()->setLatchBorrowLimit(inst, limit);
|
|
}
|
|
|
|
void
|
|
set_latch_borrow_limit_clk(Clock *clk, float limit)
|
|
{
|
|
Sta::sta()->setLatchBorrowLimit(clk, limit);
|
|
}
|
|
|
|
void
|
|
set_min_pulse_width_global(const RiseFallBoth *rf,
|
|
float min_width)
|
|
{
|
|
Sta::sta()->setMinPulseWidth(rf, min_width);
|
|
}
|
|
|
|
void
|
|
set_min_pulse_width_pin(Pin *pin,
|
|
const RiseFallBoth *rf,
|
|
float min_width)
|
|
{
|
|
Sta::sta()->setMinPulseWidth(pin, rf, min_width);
|
|
}
|
|
|
|
void
|
|
set_min_pulse_width_clk(Clock *clk,
|
|
const RiseFallBoth *rf,
|
|
float min_width)
|
|
{
|
|
Sta::sta()->setMinPulseWidth(clk, rf, min_width);
|
|
}
|
|
|
|
void
|
|
set_min_pulse_width_inst(Instance *inst,
|
|
const RiseFallBoth *rf,
|
|
float min_width)
|
|
{
|
|
Sta::sta()->setMinPulseWidth(inst, rf, min_width);
|
|
}
|
|
|
|
void
|
|
set_max_area_cmd(float area)
|
|
{
|
|
Sta::sta()->setMaxArea(area);
|
|
}
|
|
|
|
void
|
|
set_port_fanout_limit(Port *port,
|
|
const MinMax *min_max,
|
|
float fanout)
|
|
{
|
|
Sta::sta()->setFanoutLimit(port, min_max, fanout);
|
|
}
|
|
|
|
void
|
|
set_cell_fanout_limit(Cell *cell,
|
|
const MinMax *min_max,
|
|
float fanout)
|
|
{
|
|
Sta::sta()->setFanoutLimit(cell, min_max, fanout);
|
|
}
|
|
|
|
void
|
|
set_logic_value_cmd(Pin *pin,
|
|
LogicValue value)
|
|
{
|
|
Sta::sta()->setLogicValue(pin, value);
|
|
}
|
|
|
|
void
|
|
set_case_analysis_cmd(Pin *pin,
|
|
LogicValue value)
|
|
{
|
|
Sta::sta()->setCaseAnalysis(pin, value);
|
|
}
|
|
|
|
void
|
|
unset_case_analysis_cmd(Pin *pin)
|
|
{
|
|
Sta::sta()->removeCaseAnalysis(pin);
|
|
}
|
|
|
|
void
|
|
set_timing_derate_cmd(TimingDerateType type,
|
|
PathClkOrData clk_data,
|
|
const RiseFallBoth *rf,
|
|
const EarlyLate *early_late,
|
|
float derate)
|
|
{
|
|
Sta::sta()->setTimingDerate(type, clk_data, rf, early_late, derate);
|
|
}
|
|
|
|
void
|
|
set_timing_derate_net_cmd(const Net *net,
|
|
PathClkOrData clk_data,
|
|
const RiseFallBoth *rf,
|
|
const EarlyLate *early_late,
|
|
float derate)
|
|
{
|
|
Sta::sta()->setTimingDerate(net, clk_data, rf, early_late, derate);
|
|
}
|
|
|
|
void
|
|
set_timing_derate_inst_cmd(const Instance *inst,
|
|
TimingDerateCellType type,
|
|
PathClkOrData clk_data,
|
|
const RiseFallBoth *rf,
|
|
const EarlyLate *early_late,
|
|
float derate)
|
|
{
|
|
Sta::sta()->setTimingDerate(inst, type, clk_data, rf, early_late, derate);
|
|
}
|
|
|
|
void
|
|
set_timing_derate_cell_cmd(const LibertyCell *cell,
|
|
TimingDerateCellType type,
|
|
PathClkOrData clk_data,
|
|
const RiseFallBoth *rf,
|
|
const EarlyLate *early_late,
|
|
float derate)
|
|
{
|
|
Sta::sta()->setTimingDerate(cell, type, clk_data, rf, early_late, derate);
|
|
}
|
|
|
|
void
|
|
unset_timing_derate_cmd()
|
|
{
|
|
Sta::sta()->unsetTimingDerate();
|
|
}
|
|
|
|
ClockIterator *
|
|
clock_iterator()
|
|
{
|
|
return new ClockIterator(Sta::sta()->sdc());
|
|
}
|
|
|
|
Clock *
|
|
find_clock(const char *name)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->sdc()->findClock(name);
|
|
}
|
|
|
|
bool
|
|
is_clock_src(const Pin *pin)
|
|
{
|
|
return Sta::sta()->isClockSrc(pin);
|
|
}
|
|
|
|
Clock *
|
|
default_arrival_clock()
|
|
{
|
|
return Sta::sta()->sdc()->defaultArrivalClock();
|
|
}
|
|
|
|
ClockSeq *
|
|
find_clocks_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
cmdLinkedNetwork();
|
|
ClockSeq *clks = new ClockSeq;
|
|
Sta *sta = Sta::sta();
|
|
Sdc *sdc = sta->sdc();
|
|
PatternMatch matcher(pattern, regexp, nocase, sta->tclInterp());
|
|
sdc->findClocksMatching(&matcher, clks);
|
|
return clks;
|
|
}
|
|
|
|
void
|
|
update_generated_clks()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->updateGeneratedClks();
|
|
}
|
|
|
|
bool
|
|
is_clock(Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->isClock(pin);
|
|
}
|
|
|
|
bool
|
|
is_ideal_clock(Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->isIdealClock(pin);
|
|
}
|
|
|
|
bool
|
|
is_clock_search(const Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Graph *graph = sta->graph();
|
|
Search *search = sta->search();
|
|
Vertex *vertex, *bidirect_drvr_vertex;
|
|
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
|
return search->isClock(vertex);
|
|
}
|
|
|
|
bool
|
|
is_genclk_src(const Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Graph *graph = sta->graph();
|
|
Search *search = sta->search();
|
|
Vertex *vertex, *bidirect_drvr_vertex;
|
|
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
|
return search->isGenClkSrc(vertex);
|
|
}
|
|
|
|
// format_unit functions print with fixed digits and suffix.
|
|
// Pass value arg as string to support NaNs.
|
|
const char *
|
|
format_time(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
return Sta::sta()->units()->timeUnit()->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_capacitance(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
return Sta::sta()->units()->capacitanceUnit()->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_resistance(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
return Sta::sta()->units()->resistanceUnit()->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_voltage(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
return Sta::sta()->units()->voltageUnit()->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_power(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
return Sta::sta()->units()->powerUnit()->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_distance(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
Unit *dist_unit = Sta::sta()->units()->distanceUnit();
|
|
return dist_unit->asString(value1, digits);
|
|
}
|
|
|
|
const char *
|
|
format_area(const char *value,
|
|
int digits)
|
|
{
|
|
float value1 = strtof(value, nullptr);
|
|
Unit *dist_unit = Sta::sta()->units()->distanceUnit();
|
|
return dist_unit->asString(value1 / dist_unit->scale(), digits);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// <unit>_sta_ui conversion from sta units to user interface units.
|
|
// <unit>_ui_sta conversion from user interface units to sta units.
|
|
|
|
double
|
|
time_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->timeUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
time_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->timeUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
capacitance_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->capacitanceUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
capacitance_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->capacitanceUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
resistance_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->resistanceUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
resistance_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->resistanceUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
voltage_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->voltageUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
voltage_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->voltageUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
current_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->currentUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
current_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->currentUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
power_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->powerUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
power_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->powerUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
distance_ui_sta(double value)
|
|
{
|
|
return Sta::sta()->units()->distanceUnit()->userToSta(value);
|
|
}
|
|
|
|
double
|
|
distance_sta_ui(double value)
|
|
{
|
|
return Sta::sta()->units()->distanceUnit()->staToUser(value);
|
|
}
|
|
|
|
double
|
|
area_ui_sta(double value)
|
|
{
|
|
double scale = Sta::sta()->units()->distanceUnit()->scale();
|
|
return value * scale * scale;
|
|
}
|
|
|
|
double
|
|
area_sta_ui(double value)
|
|
{
|
|
double scale = Sta::sta()->units()->distanceUnit()->scale();
|
|
return value / (scale * scale);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
set_cmd_unit_scale(const char *unit_name,
|
|
float scale)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit)
|
|
unit->setScale(scale);
|
|
}
|
|
|
|
void
|
|
set_cmd_unit_digits(const char *unit_name,
|
|
int digits)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit)
|
|
unit->setDigits(digits);
|
|
}
|
|
|
|
void
|
|
set_cmd_unit_suffix(const char *unit_name,
|
|
const char *suffix)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit) {
|
|
unit->setSuffix(suffix);
|
|
}
|
|
}
|
|
|
|
const char *
|
|
unit_scale_abreviation(const char *unit_name)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit)
|
|
return unit->scaleAbreviation();
|
|
else
|
|
return "";
|
|
}
|
|
|
|
const char *
|
|
unit_suffix(const char *unit_name)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit)
|
|
return unit->suffix();
|
|
else
|
|
return "";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
VertexIterator *
|
|
vertex_iterator()
|
|
{
|
|
return new VertexIterator(cmdGraph());
|
|
}
|
|
|
|
void
|
|
set_arc_delay(Edge *edge,
|
|
TimingArc *arc,
|
|
const Corner *corner,
|
|
const MinMaxAll *min_max,
|
|
float delay)
|
|
{
|
|
cmdGraph();
|
|
Sta::sta()->setArcDelay(edge, arc, corner, min_max, delay);
|
|
}
|
|
|
|
void
|
|
set_annotated_slew(Vertex *vertex,
|
|
const Corner *corner,
|
|
const MinMaxAll *min_max,
|
|
const RiseFallBoth *rf,
|
|
float slew)
|
|
{
|
|
cmdGraph();
|
|
Sta::sta()->setAnnotatedSlew(vertex, corner, min_max, rf, slew);
|
|
}
|
|
|
|
// Remove all delay and slew annotations.
|
|
void
|
|
remove_delay_slew_annotations()
|
|
{
|
|
cmdGraph();
|
|
Sta::sta()->removeDelaySlewAnnotations();
|
|
}
|
|
|
|
CheckErrorSeq &
|
|
check_timing_cmd(bool no_input_delay,
|
|
bool no_output_delay,
|
|
bool reg_multiple_clks,
|
|
bool reg_no_clks,
|
|
bool unconstrained_endpoints,
|
|
bool loops,
|
|
bool generated_clks)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkTiming(no_input_delay, no_output_delay,
|
|
reg_multiple_clks, reg_no_clks,
|
|
unconstrained_endpoints,
|
|
loops, generated_clks);
|
|
}
|
|
|
|
bool
|
|
crpr_enabled()
|
|
{
|
|
return Sta::sta()->crprEnabled();
|
|
}
|
|
|
|
void
|
|
set_crpr_enabled(bool enabled)
|
|
{
|
|
return Sta::sta()->setCrprEnabled(enabled);
|
|
}
|
|
|
|
const char *
|
|
crpr_mode()
|
|
{
|
|
switch (Sta::sta()->crprMode()) {
|
|
case CrprMode::same_transition:
|
|
return "same_transition";
|
|
case CrprMode::same_pin:
|
|
return "same_pin";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void
|
|
set_crpr_mode(const char *mode)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
if (stringEq(mode, "same_pin"))
|
|
Sta::sta()->setCrprMode(CrprMode::same_pin);
|
|
else if (stringEq(mode, "same_transition"))
|
|
Sta::sta()->setCrprMode(CrprMode::same_transition);
|
|
else
|
|
sta->report()->critical(272, "unknown common clk pessimism mode.");
|
|
}
|
|
|
|
bool
|
|
pocv_enabled()
|
|
{
|
|
return Sta::sta()->pocvEnabled();
|
|
}
|
|
|
|
void
|
|
set_pocv_enabled(bool enabled)
|
|
{
|
|
#if !SSTA
|
|
if (enabled)
|
|
Sta::sta()->report()->error(204, "POCV support requires compilation with SSTA=1.");
|
|
#endif
|
|
return Sta::sta()->setPocvEnabled(enabled);
|
|
}
|
|
|
|
float
|
|
pocv_sigma_factor()
|
|
{
|
|
return Sta::sta()->sigmaFactor();
|
|
}
|
|
|
|
void
|
|
set_pocv_sigma_factor(float factor)
|
|
{
|
|
Sta::sta()->setSigmaFactor(factor);
|
|
}
|
|
|
|
bool
|
|
propagate_gated_clock_enable()
|
|
{
|
|
return Sta::sta()->propagateGatedClockEnable();
|
|
}
|
|
|
|
void
|
|
set_propagate_gated_clock_enable(bool enable)
|
|
{
|
|
Sta::sta()->setPropagateGatedClockEnable(enable);
|
|
}
|
|
|
|
bool
|
|
preset_clr_arcs_enabled()
|
|
{
|
|
return Sta::sta()->presetClrArcsEnabled();
|
|
}
|
|
|
|
void
|
|
set_preset_clr_arcs_enabled(bool enable)
|
|
{
|
|
Sta::sta()->setPresetClrArcsEnabled(enable);
|
|
}
|
|
|
|
bool
|
|
cond_default_arcs_enabled()
|
|
{
|
|
return Sta::sta()->condDefaultArcsEnabled();
|
|
}
|
|
|
|
void
|
|
set_cond_default_arcs_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setCondDefaultArcsEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
bidirect_inst_paths_enabled()
|
|
{
|
|
return Sta::sta()->bidirectInstPathsEnabled();
|
|
}
|
|
|
|
void
|
|
set_bidirect_inst_paths_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setBidirectInstPathsEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
bidirect_net_paths_enabled()
|
|
{
|
|
return Sta::sta()->bidirectNetPathsEnabled();
|
|
}
|
|
|
|
void
|
|
set_bidirect_net_paths_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setBidirectNetPathsEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
recovery_removal_checks_enabled()
|
|
{
|
|
return Sta::sta()->recoveryRemovalChecksEnabled();
|
|
}
|
|
|
|
void
|
|
set_recovery_removal_checks_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setRecoveryRemovalChecksEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
gated_clk_checks_enabled()
|
|
{
|
|
return Sta::sta()->gatedClkChecksEnabled();
|
|
}
|
|
|
|
void
|
|
set_gated_clk_checks_enabled(bool enabled)
|
|
{
|
|
Sta::sta()->setGatedClkChecksEnabled(enabled);
|
|
}
|
|
|
|
bool
|
|
dynamic_loop_breaking()
|
|
{
|
|
return Sta::sta()->dynamicLoopBreaking();
|
|
}
|
|
|
|
void
|
|
set_dynamic_loop_breaking(bool enable)
|
|
{
|
|
Sta::sta()->setDynamicLoopBreaking(enable);
|
|
}
|
|
|
|
bool
|
|
use_default_arrival_clock()
|
|
{
|
|
return Sta::sta()->useDefaultArrivalClock();
|
|
}
|
|
|
|
void
|
|
set_use_default_arrival_clock(bool enable)
|
|
{
|
|
return Sta::sta()->setUseDefaultArrivalClock(enable);
|
|
}
|
|
|
|
bool
|
|
propagate_all_clocks()
|
|
{
|
|
return Sta::sta()->propagateAllClocks();
|
|
}
|
|
|
|
void
|
|
set_propagate_all_clocks(bool prop)
|
|
{
|
|
Sta::sta()->setPropagateAllClocks(prop);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
PathEndSeq *
|
|
find_path_ends(ExceptionFrom *from,
|
|
ExceptionThruSeq *thrus,
|
|
ExceptionTo *to,
|
|
bool unconstrained,
|
|
Corner *corner,
|
|
const MinMaxAll *delay_min_max,
|
|
int group_count,
|
|
int endpoint_count,
|
|
bool unique_pins,
|
|
float slack_min,
|
|
float slack_max,
|
|
bool sort_by_slack,
|
|
PathGroupNameSet *groups,
|
|
bool setup,
|
|
bool hold,
|
|
bool recovery,
|
|
bool removal,
|
|
bool clk_gating_setup,
|
|
bool clk_gating_hold)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
PathEndSeq *ends = sta->findPathEnds(from, thrus, to, unconstrained,
|
|
corner, delay_min_max,
|
|
group_count, endpoint_count, unique_pins,
|
|
slack_min, slack_max,
|
|
sort_by_slack,
|
|
groups->size() ? groups : nullptr,
|
|
setup, hold,
|
|
recovery, removal,
|
|
clk_gating_setup, clk_gating_hold);
|
|
delete groups;
|
|
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)
|
|
{
|
|
Sta::sta()->setReportPathFormat(format);
|
|
}
|
|
|
|
void
|
|
set_report_path_field_order(StringSeq *field_names)
|
|
{
|
|
Sta::sta()->setReportPathFieldOrder(field_names);
|
|
delete field_names;
|
|
}
|
|
|
|
void
|
|
set_report_path_fields(bool report_input_pin,
|
|
bool report_net,
|
|
bool report_cap,
|
|
bool report_slew)
|
|
{
|
|
Sta::sta()->setReportPathFields(report_input_pin,
|
|
report_net,
|
|
report_cap,
|
|
report_slew);
|
|
}
|
|
|
|
void
|
|
set_report_path_field_properties(const char *field_name,
|
|
const char *title,
|
|
int width,
|
|
bool left_justify)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
ReportField *field = sta->findReportPathField(field_name);
|
|
if (field)
|
|
field->setProperties(title, width, left_justify);
|
|
else
|
|
sta->report()->error(607, "unknown report path field %s", field_name);
|
|
}
|
|
|
|
void
|
|
set_report_path_field_width(const char *field_name,
|
|
int width)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
ReportField *field = sta->findReportPathField(field_name);
|
|
if (field)
|
|
field->setWidth(width);
|
|
else
|
|
sta->report()->error(608, "unknown report path field %s", field_name);
|
|
}
|
|
|
|
void
|
|
set_report_path_digits(int digits)
|
|
{
|
|
Sta::sta()->setReportPathDigits(digits);
|
|
}
|
|
|
|
void
|
|
set_report_path_no_split(bool no_split)
|
|
{
|
|
Sta::sta()->setReportPathNoSplit(no_split);
|
|
}
|
|
|
|
void
|
|
set_report_path_sigmas(bool report_sigmas)
|
|
{
|
|
Sta::sta()->setReportPathSigmas(report_sigmas);
|
|
}
|
|
|
|
void
|
|
delete_path_ref(PathRef *path)
|
|
{
|
|
delete path;
|
|
}
|
|
|
|
void
|
|
remove_constraints()
|
|
{
|
|
Sta::sta()->removeConstraints();
|
|
}
|
|
|
|
void
|
|
report_path_cmd(PathRef *path)
|
|
{
|
|
Sta::sta()->reportPath(path);
|
|
}
|
|
|
|
void
|
|
report_clk_skew(ClockSet *clks,
|
|
const Corner *corner,
|
|
const SetupHold *setup_hold,
|
|
int digits)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->reportClkSkew(clks, corner, setup_hold, digits);
|
|
delete clks;
|
|
}
|
|
|
|
float
|
|
worst_clk_skew_cmd(const SetupHold *setup_hold)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->findWorstClkSkew(setup_hold);
|
|
}
|
|
|
|
TmpPinSet *
|
|
startpoints()
|
|
{
|
|
return findStartpoints();
|
|
}
|
|
|
|
TmpPinSet *
|
|
endpoints()
|
|
{
|
|
return findEndpoints();
|
|
}
|
|
|
|
TmpPinSet *
|
|
group_path_pins(const char *group_path_name)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Sdc *sdc = sta->sdc();
|
|
if (sdc->isGroupPathName(group_path_name))
|
|
return sta->findGroupPathPins(group_path_name);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
MinPulseWidthCheckSeq &
|
|
min_pulse_width_violations(const Corner *corner)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->minPulseWidthViolations(corner);
|
|
}
|
|
|
|
MinPulseWidthCheckSeq &
|
|
min_pulse_width_check_pins(PinSeq *pins,
|
|
const Corner *corner)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
MinPulseWidthCheckSeq &checks = sta->minPulseWidthChecks(pins, corner);
|
|
delete pins;
|
|
return checks;
|
|
}
|
|
|
|
MinPulseWidthCheckSeq &
|
|
min_pulse_width_checks(const Corner *corner)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->minPulseWidthChecks(corner);
|
|
}
|
|
|
|
MinPulseWidthCheck *
|
|
min_pulse_width_check_slack(const Corner *corner)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->minPulseWidthSlack(corner);
|
|
}
|
|
|
|
void
|
|
report_mpw_checks(MinPulseWidthCheckSeq *checks,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportMpwChecks(checks, verbose);
|
|
}
|
|
|
|
void
|
|
report_mpw_check(MinPulseWidthCheck *check,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportMpwCheck(check, verbose);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
MinPeriodCheckSeq &
|
|
min_period_violations()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->minPeriodViolations();
|
|
}
|
|
|
|
MinPeriodCheck *
|
|
min_period_check_slack()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->minPeriodSlack();
|
|
}
|
|
|
|
void
|
|
report_min_period_checks(MinPeriodCheckSeq *checks,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportChecks(checks, verbose);
|
|
}
|
|
|
|
void
|
|
report_min_period_check(MinPeriodCheck *check,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportCheck(check, verbose);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
MaxSkewCheckSeq &
|
|
max_skew_violations()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->maxSkewViolations();
|
|
}
|
|
|
|
MaxSkewCheck *
|
|
max_skew_check_slack()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->maxSkewSlack();
|
|
}
|
|
|
|
void
|
|
report_max_skew_checks(MaxSkewCheckSeq *checks,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportChecks(checks, verbose);
|
|
}
|
|
|
|
void
|
|
report_max_skew_check(MaxSkewCheck *check,
|
|
bool verbose)
|
|
{
|
|
Sta::sta()->reportCheck(check, verbose);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
find_timing_cmd(bool full)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->updateTiming(full);
|
|
}
|
|
|
|
void
|
|
find_requireds()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->findRequireds();
|
|
}
|
|
|
|
void
|
|
find_delays()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->findDelays();
|
|
}
|
|
|
|
Slack
|
|
total_negative_slack_cmd(const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
return sta->totalNegativeSlack(min_max);
|
|
}
|
|
|
|
Slack
|
|
total_negative_slack_corner_cmd(const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
return sta->totalNegativeSlack(corner, min_max);
|
|
}
|
|
|
|
Slack
|
|
worst_slack_cmd(const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Slack worst_slack;
|
|
Vertex *worst_vertex;
|
|
sta->worstSlack(min_max, worst_slack, worst_vertex);
|
|
return worst_slack;
|
|
}
|
|
|
|
Vertex *
|
|
worst_slack_vertex(const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Slack worst_slack;
|
|
Vertex *worst_vertex;
|
|
sta->worstSlack(min_max, worst_slack, worst_vertex);
|
|
return worst_vertex;;
|
|
}
|
|
|
|
Slack
|
|
worst_slack_corner(const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Slack worst_slack;
|
|
Vertex *worst_vertex;
|
|
sta->worstSlack(corner, min_max, worst_slack, worst_vertex);
|
|
return worst_slack;
|
|
}
|
|
|
|
PathRef *
|
|
vertex_worst_arrival_path(Vertex *vertex,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
PathRef path = sta->vertexWorstArrivalPath(vertex, min_max);
|
|
if (!path.isNull())
|
|
return new PathRef(path);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
PathRef *
|
|
vertex_worst_arrival_path_rf(Vertex *vertex,
|
|
const RiseFall *rf,
|
|
MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max);
|
|
if (!path.isNull())
|
|
return new PathRef(path);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
PathRef *
|
|
vertex_worst_slack_path(Vertex *vertex,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
PathRef path = sta->vertexWorstSlackPath(vertex, min_max);
|
|
if (!path.isNull())
|
|
return new PathRef(path);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
Slack
|
|
find_clk_min_period(const Clock *clk,
|
|
bool ignore_port_paths)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
return sta->findClkMinPeriod(clk, ignore_port_paths);
|
|
}
|
|
|
|
TmpString *
|
|
report_delay_calc_cmd(Edge *edge,
|
|
TimingArc *arc,
|
|
const Corner *corner,
|
|
const MinMax *min_max,
|
|
int digits)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
PinSeq *
|
|
check_slew_limits(Net *net,
|
|
bool violators,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkSlewLimits(net, violators, corner, min_max);
|
|
}
|
|
|
|
size_t
|
|
max_slew_violation_count()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkSlewLimits(nullptr, true, nullptr, MinMax::max())->size();
|
|
}
|
|
|
|
float
|
|
max_slew_check_slack()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
Slew slew;
|
|
float slack;
|
|
float limit;
|
|
sta->maxSlewCheck(pin, slew, slack, limit);
|
|
return sta->units()->timeUnit()->staToUser(slack);
|
|
}
|
|
|
|
float
|
|
max_slew_check_limit()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
Slew slew;
|
|
float slack;
|
|
float limit;
|
|
sta->maxSlewCheck(pin, slew, slack, limit);
|
|
return sta->units()->timeUnit()->staToUser(limit);
|
|
}
|
|
|
|
void
|
|
report_slew_limit_short_header()
|
|
{
|
|
Sta::sta()->reportSlewLimitShortHeader();
|
|
}
|
|
|
|
void
|
|
report_slew_limit_short(Pin *pin,
|
|
const Corner *corner,
|
|
const MinMax *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, corner, min_max);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
PinSeq *
|
|
check_fanout_limits(Net *net,
|
|
bool violators,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkFanoutLimits(net, violators, min_max);
|
|
}
|
|
|
|
size_t
|
|
max_fanout_violation_count()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkFanoutLimits(nullptr, true, MinMax::max())->size();
|
|
}
|
|
|
|
float
|
|
max_fanout_check_slack()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
float fanout;
|
|
float slack;
|
|
float limit;
|
|
sta->maxFanoutCheck(pin, fanout, slack, limit);
|
|
return slack;;
|
|
}
|
|
|
|
float
|
|
max_fanout_check_limit()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
float fanout;
|
|
float slack;
|
|
float limit;
|
|
sta->maxFanoutCheck(pin, fanout, slack, limit);
|
|
return limit;;
|
|
}
|
|
|
|
void
|
|
report_fanout_limit_short_header()
|
|
{
|
|
Sta::sta()->reportFanoutLimitShortHeader();
|
|
}
|
|
|
|
void
|
|
report_fanout_limit_short(Pin *pin,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta::sta()->reportFanoutLimitShort(pin, min_max);
|
|
}
|
|
|
|
void
|
|
report_fanout_limit_verbose(Pin *pin,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta::sta()->reportFanoutLimitVerbose(pin, min_max);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
PinSeq *
|
|
check_capacitance_limits(Net *net,
|
|
bool violators,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkCapacitanceLimits(net, violators, corner, min_max);
|
|
}
|
|
|
|
size_t
|
|
max_capacitance_violation_count()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->checkCapacitanceLimits(nullptr, true,nullptr,MinMax::max())->size();
|
|
}
|
|
|
|
float
|
|
max_capacitance_check_slack()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
float capacitance;
|
|
float slack;
|
|
float limit;
|
|
sta->maxCapacitanceCheck(pin, capacitance, slack, limit);
|
|
return sta->units()->capacitanceUnit()->staToUser(slack);
|
|
}
|
|
|
|
float
|
|
max_capacitance_check_limit()
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
Pin *pin;
|
|
float capacitance;
|
|
float slack;
|
|
float limit;
|
|
sta->maxCapacitanceCheck(pin, capacitance, slack, limit);
|
|
return sta->units()->capacitanceUnit()->staToUser(limit);
|
|
}
|
|
|
|
void
|
|
report_capacitance_limit_short_header()
|
|
{
|
|
Sta::sta()->reportCapacitanceLimitShortHeader();
|
|
}
|
|
|
|
void
|
|
report_capacitance_limit_short(Pin *pin,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta::sta()->reportCapacitanceLimitShort(pin, corner, min_max);
|
|
}
|
|
|
|
void
|
|
report_capacitance_limit_verbose(Pin *pin,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta::sta()->reportCapacitanceLimitVerbose(pin, corner, min_max);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
EdgeSeq *
|
|
disabled_edges_sorted()
|
|
{
|
|
cmdLinkedNetwork();
|
|
return Sta::sta()->disabledEdgesSorted();
|
|
}
|
|
|
|
void
|
|
write_sdc_cmd(const char *filename,
|
|
bool leaf,
|
|
bool compatible,
|
|
int digits,
|
|
bool gzip,
|
|
bool no_timestamp)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta::sta()->writeSdc(filename, leaf, compatible, digits, gzip, no_timestamp);
|
|
}
|
|
|
|
void
|
|
write_path_spice_cmd(PathRef *path,
|
|
const char *spice_filename,
|
|
const char *subckt_filename,
|
|
const char *lib_subckt_filename,
|
|
const char *model_filename,
|
|
const char *power_name,
|
|
const char *gnd_name)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
writePathSpice(path, spice_filename, subckt_filename,
|
|
lib_subckt_filename, model_filename,
|
|
power_name, gnd_name, sta);
|
|
}
|
|
|
|
void
|
|
write_timing_model_cmd(const char *lib_name,
|
|
const char *cell_name,
|
|
const char *filename,
|
|
const Corner *corner)
|
|
{
|
|
Sta::sta()->writeTimingModel(lib_name, cell_name, filename, corner);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
liberty_supply_exists(const char *supply_name)
|
|
{
|
|
auto network = Sta::sta()->network();
|
|
auto lib = network->defaultLibertyLibrary();
|
|
return lib && lib->supplyExists(supply_name);
|
|
}
|
|
|
|
float
|
|
unit_scale(const char *unit_name)
|
|
{
|
|
Unit *unit = Sta::sta()->units()->find(unit_name);
|
|
if (unit)
|
|
return unit->scale();
|
|
else
|
|
return 1.0F;
|
|
}
|
|
|
|
bool
|
|
fuzzy_equal(float value1,
|
|
float value2)
|
|
{
|
|
return fuzzyEqual(value1, value2);
|
|
}
|
|
|
|
char
|
|
pin_sim_logic_value(const Pin *pin)
|
|
{
|
|
return logicValueString(Sta::sta()->simLogicValue(pin));
|
|
}
|
|
|
|
char
|
|
pin_case_logic_value(const Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Sdc *sdc = sta->sdc();
|
|
LogicValue value = LogicValue::unknown;
|
|
bool exists;
|
|
sdc->caseLogicValue(pin, value, exists);
|
|
return logicValueString(value);
|
|
}
|
|
|
|
char
|
|
pin_logic_value(const Pin *pin)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Sdc *sdc = sta->sdc();
|
|
LogicValue value = LogicValue::unknown;
|
|
bool exists;
|
|
sdc->logicValue(pin, value, exists);
|
|
return logicValueString(value);
|
|
}
|
|
|
|
SlowDrvrIterator *
|
|
slow_driver_iterator()
|
|
{
|
|
return Sta::sta()->slowDrvrIterator();
|
|
}
|
|
|
|
bool
|
|
timing_arc_disabled(Edge *edge,
|
|
TimingArc *arc)
|
|
{
|
|
Graph *graph = Sta::sta()->graph();
|
|
return !searchThru(edge, arc, graph);
|
|
}
|
|
|
|
ClockGroups *
|
|
make_clock_groups(const char *name,
|
|
bool logically_exclusive,
|
|
bool physically_exclusive,
|
|
bool asynchronous,
|
|
bool allow_paths,
|
|
const char *comment)
|
|
{
|
|
return Sta::sta()->makeClockGroups(name, logically_exclusive,
|
|
physically_exclusive, asynchronous,
|
|
allow_paths, comment);
|
|
}
|
|
|
|
void
|
|
clock_groups_make_group(ClockGroups *clk_groups,
|
|
ClockSet *clks)
|
|
{
|
|
Sta::sta()->makeClockGroup(clk_groups, clks);
|
|
}
|
|
|
|
void
|
|
unset_clock_groups_logically_exclusive(const char *name)
|
|
{
|
|
Sta::sta()->removeClockGroupsLogicallyExclusive(name);
|
|
}
|
|
|
|
void
|
|
unset_clock_groups_physically_exclusive(const char *name)
|
|
{
|
|
Sta::sta()->removeClockGroupsPhysicallyExclusive(name);
|
|
}
|
|
|
|
void
|
|
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->sameClockGroupExplicit(clk1, clk2);
|
|
}
|
|
|
|
void
|
|
set_clock_sense_cmd(PinSet *pins,
|
|
ClockSet *clks,
|
|
bool positive,
|
|
bool negative,
|
|
bool stop_propagation)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
if (positive)
|
|
sta->setClockSense(pins, clks, ClockSense::positive);
|
|
else if (negative)
|
|
sta->setClockSense(pins, clks, ClockSense::negative);
|
|
else if (stop_propagation)
|
|
sta->setClockSense(pins, clks, ClockSense::stop);
|
|
else
|
|
sta->report()->critical(273, "unknown clock sense");
|
|
}
|
|
|
|
bool
|
|
timing_role_is_check(TimingRole *role)
|
|
{
|
|
return role->isTimingCheck();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TmpPinSet *
|
|
find_fanin_pins(PinSeq *to,
|
|
bool flat,
|
|
bool startpoints_only,
|
|
int inst_levels,
|
|
int pin_levels,
|
|
bool thru_disabled,
|
|
bool thru_constants)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
PinSet *fanin = sta->findFaninPins(to, flat, startpoints_only,
|
|
inst_levels, pin_levels,
|
|
thru_disabled, thru_constants);
|
|
delete to;
|
|
return fanin;
|
|
}
|
|
|
|
TmpInstanceSet *
|
|
find_fanin_insts(PinSeq *to,
|
|
bool flat,
|
|
bool startpoints_only,
|
|
int inst_levels,
|
|
int pin_levels,
|
|
bool thru_disabled,
|
|
bool thru_constants)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
InstanceSet *fanin = sta->findFaninInstances(to, flat, startpoints_only,
|
|
inst_levels, pin_levels,
|
|
thru_disabled, thru_constants);
|
|
delete to;
|
|
return fanin;
|
|
}
|
|
|
|
TmpPinSet *
|
|
find_fanout_pins(PinSeq *from,
|
|
bool flat,
|
|
bool endpoints_only,
|
|
int inst_levels,
|
|
int pin_levels,
|
|
bool thru_disabled,
|
|
bool thru_constants)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
PinSet *fanout = sta->findFanoutPins(from, flat, endpoints_only,
|
|
inst_levels, pin_levels,
|
|
thru_disabled, thru_constants);
|
|
delete from;
|
|
return fanout;
|
|
}
|
|
|
|
TmpInstanceSet *
|
|
find_fanout_insts(PinSeq *from,
|
|
bool flat,
|
|
bool endpoints_only,
|
|
int inst_levels,
|
|
int pin_levels,
|
|
bool thru_disabled,
|
|
bool thru_constants)
|
|
{
|
|
cmdLinkedNetwork();
|
|
Sta *sta = Sta::sta();
|
|
InstanceSet *fanout = sta->findFanoutInstances(from, flat, endpoints_only,
|
|
inst_levels, pin_levels,
|
|
thru_disabled, thru_constants);
|
|
delete from;
|
|
return fanout;
|
|
}
|
|
|
|
TmpPinSet *
|
|
net_load_pins(Net *net)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
PinSet *pins = new PinSet;
|
|
NetConnectedPinIterator *pin_iter = network->connectedPinIterator(net);
|
|
while (pin_iter->hasNext()) {
|
|
Pin *pin = pin_iter->next();
|
|
if (network->isLoad(pin))
|
|
pins->insert(pin);
|
|
}
|
|
delete pin_iter;
|
|
return pins;
|
|
}
|
|
|
|
TmpPinSet *
|
|
net_driver_pins(Net *net)
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
PinSet *pins = new PinSet;
|
|
NetConnectedPinIterator *pin_iter = network->connectedPinIterator(net);
|
|
while (pin_iter->hasNext()) {
|
|
Pin *pin = pin_iter->next();
|
|
if (network->isDriver(pin))
|
|
pins->insert(pin);
|
|
}
|
|
delete pin_iter;
|
|
return pins;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
report_loops()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Network *network = cmdLinkedNetwork();
|
|
Graph *graph = cmdGraph();
|
|
Report *report = sta->report();
|
|
GraphLoopSeq *loops = sta->graphLoops();
|
|
GraphLoopSeq::Iterator loop_iter(loops);
|
|
while (loop_iter.hasNext()) {
|
|
GraphLoop *loop = loop_iter.next();
|
|
loop->report(report, network, graph);
|
|
report->reportLineString("");
|
|
}
|
|
}
|
|
|
|
// Includes top instance.
|
|
int
|
|
network_instance_count()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
return network->instanceCount();
|
|
}
|
|
|
|
int
|
|
network_pin_count()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
return network->pinCount();
|
|
}
|
|
|
|
int
|
|
network_net_count()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
return network->netCount();
|
|
}
|
|
|
|
int
|
|
network_leaf_instance_count()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
return network->leafInstanceCount();
|
|
}
|
|
|
|
int
|
|
network_leaf_pin_count()
|
|
{
|
|
Network *network = cmdNetwork();
|
|
return network->leafPinCount();
|
|
}
|
|
|
|
int
|
|
graph_vertex_count()
|
|
{
|
|
return cmdGraph()->vertexCount();
|
|
}
|
|
|
|
int
|
|
graph_edge_count()
|
|
{
|
|
return cmdGraph()->edgeCount();
|
|
}
|
|
|
|
int
|
|
graph_arc_count()
|
|
{
|
|
return cmdGraph()->arcCount();
|
|
}
|
|
|
|
int
|
|
tag_group_count()
|
|
{
|
|
return Sta::sta()->tagGroupCount();
|
|
}
|
|
|
|
void
|
|
report_tag_groups()
|
|
{
|
|
Sta::sta()->search()->reportTagGroups();
|
|
}
|
|
|
|
void
|
|
report_tag_arrivals_cmd(Vertex *vertex)
|
|
{
|
|
Sta::sta()->search()->reportArrivals(vertex);
|
|
}
|
|
|
|
void
|
|
report_arrival_count_histogram()
|
|
{
|
|
Sta::sta()->search()->reportArrivalCountHistogram();
|
|
}
|
|
|
|
int
|
|
tag_count()
|
|
{
|
|
return Sta::sta()->tagCount();
|
|
}
|
|
|
|
void
|
|
report_tags()
|
|
{
|
|
Sta::sta()->search()->reportTags();
|
|
}
|
|
|
|
void
|
|
report_clk_infos()
|
|
{
|
|
Sta::sta()->search()->reportClkInfos();
|
|
}
|
|
|
|
int
|
|
clk_info_count()
|
|
{
|
|
return Sta::sta()->clkInfoCount();
|
|
}
|
|
|
|
int
|
|
arrival_count()
|
|
{
|
|
return Sta::sta()->arrivalCount();
|
|
}
|
|
|
|
int
|
|
required_count()
|
|
{
|
|
return Sta::sta()->requiredCount();
|
|
}
|
|
|
|
int
|
|
graph_arrival_count()
|
|
{
|
|
return Sta::sta()->graph()->arrivalCount();
|
|
}
|
|
|
|
int
|
|
graph_required_count()
|
|
{
|
|
return Sta::sta()->graph()->requiredCount();
|
|
}
|
|
|
|
void
|
|
delete_all_memory()
|
|
{
|
|
deleteAllMemory();
|
|
}
|
|
|
|
Tcl_Interp *
|
|
tcl_interp()
|
|
{
|
|
return Sta::sta()->tclInterp();
|
|
}
|
|
|
|
// Initialize sta after delete_all_memory.
|
|
void
|
|
init_sta()
|
|
{
|
|
initSta();
|
|
}
|
|
|
|
void
|
|
clear_sta()
|
|
{
|
|
Sta::sta()->clear();
|
|
}
|
|
|
|
void
|
|
make_sta(Tcl_Interp *interp)
|
|
{
|
|
Sta *sta = new Sta;
|
|
Sta::setSta(sta);
|
|
sta->makeComponents();
|
|
sta->setTclInterp(interp);
|
|
}
|
|
|
|
void
|
|
clear_network()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
sta->network()->clear();
|
|
}
|
|
|
|
// Elapsed run time (in seconds).
|
|
double
|
|
elapsed_run_time()
|
|
{
|
|
return elapsedRunTime();
|
|
}
|
|
|
|
// User run time (in seconds).
|
|
double
|
|
user_run_time()
|
|
{
|
|
return userRunTime();
|
|
}
|
|
|
|
// User run time (in seconds).
|
|
unsigned long
|
|
cputime()
|
|
{
|
|
return static_cast<unsigned long>(userRunTime() + .5);
|
|
}
|
|
|
|
// Peak memory usage in bytes.
|
|
unsigned long
|
|
memory_usage()
|
|
{
|
|
return memoryUsage();
|
|
}
|
|
|
|
int
|
|
processor_count()
|
|
{
|
|
return processorCount();
|
|
}
|
|
|
|
int
|
|
thread_count()
|
|
{
|
|
return Sta::sta()->threadCount();
|
|
}
|
|
|
|
void
|
|
set_thread_count(int count)
|
|
{
|
|
Sta::sta()->setThreadCount(count);
|
|
}
|
|
|
|
void
|
|
arrivals_invalid()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
sta->arrivalsInvalid();
|
|
}
|
|
|
|
void
|
|
delays_invalid()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
sta->delaysInvalid();
|
|
}
|
|
|
|
const char *
|
|
pin_location(const Pin *pin)
|
|
{
|
|
Network *network = cmdNetwork();
|
|
double x, y;
|
|
bool exists;
|
|
network->location(pin, x, y, exists);
|
|
// return x/y as tcl list
|
|
if (exists)
|
|
return sta::stringPrintTmp("%f %f", x, y);
|
|
else
|
|
return "";
|
|
}
|
|
|
|
const char *
|
|
port_location(const Port *port)
|
|
{
|
|
Network *network = cmdNetwork();
|
|
const Pin *pin = network->findPin(network->topInstance(), port);
|
|
return pin_location(pin);
|
|
}
|
|
|
|
int
|
|
endpoint_count()
|
|
{
|
|
return Sta::sta()->endpointCount();
|
|
}
|
|
|
|
%} // inline
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Object Methods
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
%extend Library {
|
|
const char *name()
|
|
{
|
|
return cmdNetwork()->name(self);
|
|
}
|
|
|
|
Cell *
|
|
find_cell(const char *name)
|
|
{
|
|
return cmdNetwork()->findCell(self, name);
|
|
}
|
|
|
|
TmpCellSeq *
|
|
find_cells_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
TmpCellSeq *cells = new TmpCellSeq;
|
|
cmdNetwork()->findCellsMatching(self, &matcher, cells);
|
|
return cells;
|
|
}
|
|
|
|
} // Library methods
|
|
|
|
%extend LibertyLibrary {
|
|
const char *name() { return self->name(); }
|
|
|
|
LibertyCell *
|
|
find_liberty_cell(const char *name)
|
|
{
|
|
return self->findLibertyCell(name);
|
|
}
|
|
|
|
TmpLibertyCellSeq *
|
|
find_liberty_cells_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
// TmpLibertyCellSeq deletes temporary CellSeq after conversion to tcl list.
|
|
TmpLibertyCellSeq *cells = new TmpLibertyCellSeq;
|
|
self->findLibertyCellsMatching(&matcher, cells);
|
|
return cells;
|
|
}
|
|
|
|
Wireload *
|
|
find_wireload(const char *model_name)
|
|
{
|
|
return self->findWireload(model_name);
|
|
}
|
|
|
|
WireloadSelection *
|
|
find_wireload_selection(const char *selection_name)
|
|
{
|
|
return self->findWireloadSelection(selection_name);
|
|
}
|
|
|
|
OperatingConditions *
|
|
find_operating_conditions(const char *op_cond_name)
|
|
{
|
|
return self->findOperatingConditions(op_cond_name);
|
|
}
|
|
|
|
OperatingConditions *
|
|
default_operating_conditions()
|
|
{
|
|
return self->defaultOperatingConditions();
|
|
}
|
|
|
|
} // LibertyLibrary methods
|
|
|
|
%extend LibraryIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Library *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // LibraryIterator methods
|
|
|
|
%extend LibertyLibraryIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
LibertyLibrary *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // LibertyLibraryIterator methods
|
|
|
|
%extend Cell {
|
|
Library *library() { return cmdNetwork()->library(self); }
|
|
LibertyCell *liberty_cell() { return cmdNetwork()->libertyCell(self); }
|
|
bool is_leaf() { return cmdNetwork()->isLeaf(self); }
|
|
CellPortIterator *
|
|
port_iterator() { return cmdNetwork()->portIterator(self); }
|
|
|
|
Port *
|
|
find_port(const char *name)
|
|
{
|
|
return cmdNetwork()->findPort(self, name);
|
|
}
|
|
|
|
TmpPortSeq *
|
|
find_ports_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
TmpPortSeq *ports = new TmpPortSeq;
|
|
cmdNetwork()->findPortsMatching(self, &matcher, ports);
|
|
return ports;
|
|
}
|
|
|
|
} // Cell methods
|
|
|
|
%extend LibertyCell {
|
|
const char *name() { return self->name(); }
|
|
bool is_leaf() { return self->isLeaf(); }
|
|
bool is_buffer() { return self->isBuffer(); }
|
|
bool is_inverter() { return self->isInverter(); }
|
|
LibertyLibrary *liberty_library() { return self->libertyLibrary(); }
|
|
Cell *cell() { return reinterpret_cast<Cell*>(self); }
|
|
LibertyPort *
|
|
find_liberty_port(const char *name)
|
|
{
|
|
return self->findLibertyPort(name);
|
|
}
|
|
|
|
TmpLibertyPortSeq *
|
|
find_liberty_ports_matching(const char *pattern,
|
|
bool regexp,
|
|
bool nocase)
|
|
{
|
|
PatternMatch matcher(pattern, regexp, nocase, Sta::sta()->tclInterp());
|
|
TmpLibertyPortSeq *ports = new TmpLibertyPortSeq;
|
|
self->findLibertyPortsMatching(&matcher, ports);
|
|
return ports;
|
|
}
|
|
|
|
LibertyCellPortIterator *
|
|
liberty_port_iterator() { return new LibertyCellPortIterator(self); }
|
|
|
|
const TimingArcSetSeq &
|
|
timing_arc_sets()
|
|
{
|
|
return self->timingArcSets();
|
|
}
|
|
|
|
} // LibertyCell methods
|
|
|
|
%extend CellPortIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Port *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // CellPortIterator methods
|
|
|
|
%extend LibertyCellPortIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
LibertyPort *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // LibertyCellPortIterator methods
|
|
|
|
%extend Port {
|
|
const char *bus_name() { return cmdNetwork()->busName(self); }
|
|
Cell *cell() { return cmdNetwork()->cell(self); }
|
|
LibertyPort *liberty_port() { return cmdNetwork()->libertyPort(self); }
|
|
bool is_bus() { return cmdNetwork()->isBus(self); }
|
|
PortMemberIterator *
|
|
member_iterator() { return cmdNetwork()->memberIterator(self); }
|
|
|
|
} // Port methods
|
|
|
|
%extend LibertyPort {
|
|
const char *bus_name() { return self->busName(); }
|
|
Cell *cell() { return self->cell(); }
|
|
bool is_bus() { return self->isBus(); }
|
|
LibertyPortMemberIterator *
|
|
member_iterator() { return new LibertyPortMemberIterator(self); }
|
|
|
|
const char *
|
|
function()
|
|
{
|
|
FuncExpr *func = self->function();
|
|
if (func)
|
|
return func->asString();
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
const char *
|
|
tristate_enable()
|
|
{
|
|
FuncExpr *enable = self->tristateEnable();
|
|
if (enable)
|
|
return enable->asString();
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
float
|
|
capacitance(Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->capacitance(self, corner, min_max);
|
|
}
|
|
|
|
} // LibertyPort methods
|
|
|
|
%extend OperatingConditions {
|
|
float process() { return self->process(); }
|
|
float voltage() { return self->voltage(); }
|
|
float temperature() { return self->temperature(); }
|
|
}
|
|
|
|
%extend PortMemberIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Port *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // PortMemberIterator methods
|
|
|
|
%extend LibertyPortMemberIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
LibertyPort *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // LibertyPortMemberIterator methods
|
|
|
|
%extend TimingArcSet {
|
|
LibertyPort *from() { return self->from(); }
|
|
LibertyPort *to() { return self->to(); }
|
|
TimingRole *role() { return self->role(); }
|
|
const char *sdf_cond() { return self->sdfCond(); }
|
|
|
|
const char *
|
|
full_name()
|
|
{
|
|
const char *from = self->from()->name();
|
|
const char *to = self->to()->name();
|
|
const char *cell_name = self->libertyCell()->name();
|
|
return stringPrintTmp("%s %s -> %s",
|
|
cell_name,
|
|
from,
|
|
to);
|
|
}
|
|
|
|
} // TimingArcSet methods
|
|
|
|
%extend TimingArc {
|
|
LibertyPort *from() { return self->from(); }
|
|
LibertyPort *to() { return self->to(); }
|
|
Transition *from_edge() { return self->fromEdge(); }
|
|
const char *from_edge_name() { return self->fromEdge()->asRiseFall()->name(); }
|
|
Transition *to_edge() { return self->toEdge(); }
|
|
const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); }
|
|
TimingRole *role() { return self->role(); }
|
|
} // TimingArc methods
|
|
|
|
%extend Instance {
|
|
Instance *parent() { return cmdLinkedNetwork()->parent(self); }
|
|
Cell *cell() { return cmdLinkedNetwork()->cell(self); }
|
|
LibertyCell *liberty_cell() { return cmdLinkedNetwork()->libertyCell(self); }
|
|
bool is_leaf() { return cmdLinkedNetwork()->isLeaf(self); }
|
|
InstanceChildIterator *
|
|
child_iterator() { return cmdLinkedNetwork()->childIterator(self); }
|
|
InstancePinIterator *
|
|
pin_iterator() { return cmdLinkedNetwork()->pinIterator(self); }
|
|
InstanceNetIterator *
|
|
net_iterator() { return cmdLinkedNetwork()->netIterator(self); }
|
|
Pin *
|
|
find_pin(const char *name)
|
|
{
|
|
return cmdLinkedNetwork()->findPin(self, name);
|
|
}
|
|
} // Instance methods
|
|
|
|
%extend InstanceChildIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Instance *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // InstanceChildIterator methods
|
|
|
|
%extend LeafInstanceIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Instance *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // LeafInstanceIterator methods
|
|
|
|
%extend InstancePinIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Pin *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // InstancePinIterator methods
|
|
|
|
%extend InstanceNetIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Net *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // InstanceNetIterator methods
|
|
|
|
%extend Pin {
|
|
const char *port_name() { return cmdLinkedNetwork()->portName(self); }
|
|
Instance *instance() { return cmdLinkedNetwork()->instance(self); }
|
|
Net *net() { return cmdLinkedNetwork()->net(self); }
|
|
Port *port() { return cmdLinkedNetwork()->port(self); }
|
|
Term *term() { return cmdLinkedNetwork()->term(self); }
|
|
LibertyPort *liberty_port() { return cmdLinkedNetwork()->libertyPort(self); }
|
|
bool is_driver() { return cmdLinkedNetwork()->isDriver(self); }
|
|
bool is_load() { return cmdLinkedNetwork()->isLoad(self); }
|
|
bool is_leaf() { return cmdLinkedNetwork()->isLeaf(self); }
|
|
bool is_hierarchical() { return cmdLinkedNetwork()->isHierarchical(self); }
|
|
bool is_top_level_port() { return cmdLinkedNetwork()->isTopLevelPort(self); }
|
|
PinConnectedPinIterator *connected_pin_iterator()
|
|
{ return cmdLinkedNetwork()->connectedPinIterator(self); }
|
|
|
|
Vertex **
|
|
vertices()
|
|
{
|
|
Vertex *vertex, *vertex_bidirect_drvr;
|
|
static Vertex *vertices[3];
|
|
|
|
cmdGraph()->pinVertices(self, vertex, vertex_bidirect_drvr);
|
|
vertices[0] = vertex;
|
|
vertices[1] = vertex_bidirect_drvr;
|
|
vertices[2] = nullptr;
|
|
return vertices;
|
|
}
|
|
|
|
} // Pin methods
|
|
|
|
%extend PinConnectedPinIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Pin *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // PinConnectedPinIterator methods
|
|
|
|
%extend Term {
|
|
Net *net() { return cmdLinkedNetwork()->net(self); }
|
|
Pin *pin() { return cmdLinkedNetwork()->pin(self); }
|
|
} // Term methods
|
|
|
|
%extend Net {
|
|
Instance *instance() { return cmdLinkedNetwork()->instance(self); }
|
|
Net *highest_connected_net()
|
|
{ return cmdLinkedNetwork()->highestConnectedNet(self); }
|
|
NetPinIterator *pin_iterator() { return cmdLinkedNetwork()->pinIterator(self);}
|
|
NetTermIterator *term_iterator() {return cmdLinkedNetwork()->termIterator(self);}
|
|
NetConnectedPinIterator *connected_pin_iterator()
|
|
{ return cmdLinkedNetwork()->connectedPinIterator(self); }
|
|
bool is_power() { return cmdLinkedNetwork()->isPower(self);}
|
|
bool is_ground() { return cmdLinkedNetwork()->isGround(self);}
|
|
|
|
float
|
|
capacitance(Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
Sta::sta()->connectedCap(self, corner, min_max, pin_cap, wire_cap);
|
|
return pin_cap + wire_cap;
|
|
}
|
|
|
|
float
|
|
pin_capacitance(Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
Sta::sta()->connectedCap(self, corner, min_max, pin_cap, wire_cap);
|
|
return pin_cap;
|
|
}
|
|
|
|
float
|
|
wire_capacitance(Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
cmdLinkedNetwork();
|
|
float pin_cap, wire_cap;
|
|
Sta::sta()->connectedCap(self, corner, min_max, pin_cap, wire_cap);
|
|
return wire_cap;
|
|
}
|
|
|
|
// get_ports -of_objects net
|
|
TmpPortSeq *
|
|
ports()
|
|
{
|
|
Network *network = cmdLinkedNetwork();
|
|
PortSeq *ports = new PortSeq;
|
|
if (network->isTopInstance(network->instance(self))) {
|
|
NetTermIterator *term_iter = network->termIterator(self);
|
|
while (term_iter->hasNext()) {
|
|
Term *term = term_iter->next();
|
|
Port *port = network->port(network->pin(term));
|
|
ports->push_back(port);
|
|
}
|
|
delete term_iter;
|
|
}
|
|
return ports;
|
|
}
|
|
|
|
} // Net methods
|
|
|
|
%extend NetPinIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Pin *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // NetPinIterator methods
|
|
|
|
%extend NetTermIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Term *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // NetTermIterator methods
|
|
|
|
%extend NetConnectedPinIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Pin *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // NetConnectedPinIterator methods
|
|
|
|
%extend Clock {
|
|
float period() { return self->period(); }
|
|
FloatSeq *waveform() { return self->waveform(); }
|
|
float time(RiseFall *rf) { return self->edge(rf)->time(); }
|
|
bool is_generated() { return self->isGenerated(); }
|
|
bool waveform_valid() { return self->waveformValid(); }
|
|
bool is_virtual() { return self->isVirtual(); }
|
|
bool is_propagated() { return self->isPropagated(); }
|
|
PinSet &sources() { return self->pins(); }
|
|
|
|
float
|
|
slew(const RiseFall *rf,
|
|
const MinMax *min_max)
|
|
{
|
|
return self->slew(rf, min_max);
|
|
}
|
|
|
|
}
|
|
|
|
%extend ClockEdge {
|
|
Clock *clock() { return self->clock(); }
|
|
RiseFall *transition() { return self->transition(); }
|
|
float time() { return self->time(); }
|
|
}
|
|
|
|
%extend ClockIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Clock *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
}
|
|
|
|
%extend Vertex {
|
|
Pin *pin() { return self->pin(); }
|
|
bool is_bidirect_driver() { return self->isBidirectDriver(); }
|
|
int level() { return Sta::sta()->vertexLevel(self); }
|
|
int tag_group_index() { return self->tagGroupIndex(); }
|
|
|
|
Slew
|
|
slew(const RiseFall *rf,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->vertexSlew(self, rf, min_max);
|
|
}
|
|
|
|
Slew
|
|
slew_corner(const RiseFall *rf,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->vertexSlew(self, rf, corner, min_max);
|
|
}
|
|
|
|
VertexOutEdgeIterator *
|
|
out_edge_iterator()
|
|
{
|
|
return new VertexOutEdgeIterator(self, Sta::sta()->graph());
|
|
}
|
|
|
|
VertexInEdgeIterator *
|
|
in_edge_iterator()
|
|
{
|
|
return new VertexInEdgeIterator(self, Sta::sta()->graph());
|
|
}
|
|
|
|
TmpFloatSeq *
|
|
arrivals_clk(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpFloatSeq *floats = new FloatSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
floats->push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge,
|
|
path_ap)));
|
|
}
|
|
return floats;
|
|
}
|
|
|
|
TmpStringSeq *
|
|
arrivals_clk_delays(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf,
|
|
int digits)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
StringSeq *arrivals = new StringSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
arrivals->push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge,
|
|
path_ap),
|
|
sta, digits));
|
|
}
|
|
return arrivals;
|
|
}
|
|
|
|
TmpFloatSeq *
|
|
requireds_clk(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpFloatSeq *floats = new FloatSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
floats->push_back(delayAsFloat(sta->vertexRequired(self, rf, clk_edge,
|
|
path_ap)));
|
|
}
|
|
return floats;
|
|
}
|
|
|
|
TmpStringSeq *
|
|
requireds_clk_delays(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf,
|
|
int digits)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
StringSeq *requireds = new StringSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
requireds->push_back(delayAsString(sta->vertexRequired(self, rf, clk_edge,
|
|
path_ap),
|
|
sta, digits));
|
|
}
|
|
return requireds;
|
|
}
|
|
|
|
Slack
|
|
slack(MinMax *min_max)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return sta->vertexSlack(self, min_max);
|
|
}
|
|
|
|
TmpFloatSeq *
|
|
slacks(RiseFall *rf)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpFloatSeq *floats = new FloatSeq;
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
floats->push_back(delayAsFloat(sta->vertexSlack(self, rf, path_ap)));
|
|
}
|
|
return floats;
|
|
}
|
|
|
|
// Slack with respect to a clock rise/fall edge.
|
|
TmpFloatSeq *
|
|
slacks_clk(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpFloatSeq *floats = new FloatSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
floats->push_back(delayAsFloat(sta->vertexSlack(self, rf, clk_edge,
|
|
path_ap)));
|
|
}
|
|
return floats;
|
|
}
|
|
|
|
TmpStringSeq *
|
|
slacks_clk_delays(const RiseFall *rf,
|
|
Clock *clk,
|
|
const RiseFall *clk_rf,
|
|
int digits)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
StringSeq *slacks = new StringSeq;
|
|
const ClockEdge *clk_edge = nullptr;
|
|
if (clk)
|
|
clk_edge = clk->edge(clk_rf);
|
|
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
|
|
slacks->push_back(delayAsString(sta->vertexSlack(self, rf, clk_edge,
|
|
path_ap),
|
|
sta, digits));
|
|
}
|
|
return slacks;
|
|
}
|
|
|
|
VertexPathIterator *
|
|
path_iterator(const RiseFall *rf,
|
|
const MinMax *min_max)
|
|
{
|
|
return Sta::sta()->vertexPathIterator(self, rf, min_max);
|
|
}
|
|
|
|
bool
|
|
has_downstream_clk_pin()
|
|
{
|
|
return self->hasDownstreamClkPin();
|
|
}
|
|
|
|
bool
|
|
is_clock()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
Search *search = sta->search();
|
|
return search->isClock(self);
|
|
}
|
|
|
|
bool is_disabled_constraint() { return self->isDisabledConstraint(); }
|
|
|
|
} // Vertex methods
|
|
|
|
%extend Edge {
|
|
Vertex *from() { return self->from(Sta::sta()->graph()); }
|
|
Vertex *to() { return self->to(Sta::sta()->graph()); }
|
|
Pin *from_pin() { return self->from(Sta::sta()->graph())->pin(); }
|
|
Pin *to_pin() { return self->to(Sta::sta()->graph())->pin(); }
|
|
TimingRole *role() { return self->role(); }
|
|
const char *sense() { return timingSenseString(self->sense()); }
|
|
const TimingArcSeq &
|
|
timing_arcs() { return self->timingArcSet()->arcs(); }
|
|
bool is_disabled_loop() { return Sta::sta()->isDisabledLoop(self); }
|
|
bool is_disabled_constraint() { return Sta::sta()->isDisabledConstraint(self);}
|
|
bool is_disabled_constant() { return Sta::sta()->isDisabledConstant(self); }
|
|
bool is_disabled_cond_default()
|
|
{ return Sta::sta()->isDisabledCondDefault(self); }
|
|
TmpPinSet *
|
|
disabled_constant_pins() { return Sta::sta()->disabledConstantPins(self); }
|
|
bool is_disabled_bidirect_inst_path()
|
|
{ return Sta::sta()->isDisabledBidirectInstPath(self); }
|
|
bool is_disabled_bidirect_net_path()
|
|
{ return Sta::sta()->isDisabledBidirectNetPath(self); }
|
|
bool is_disabled_preset_clear()
|
|
{ return Sta::sta()->isDisabledPresetClr(self); }
|
|
const char *
|
|
sim_timing_sense(){return timingSenseString(Sta::sta()->simTimingSense(self));}
|
|
|
|
TmpFloatSeq *
|
|
arc_delays(TimingArc *arc)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
TmpFloatSeq *floats = new FloatSeq;
|
|
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
|
|
floats->push_back(delayAsFloat(sta->arcDelay(self, arc, dcalc_ap)));
|
|
return floats;
|
|
}
|
|
|
|
TmpStringSeq *
|
|
arc_delay_strings(TimingArc *arc,
|
|
int digits)
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
StringSeq *delays = new StringSeq;
|
|
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
|
|
delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap),
|
|
sta, digits));
|
|
return delays;
|
|
}
|
|
|
|
bool
|
|
delay_annotated(TimingArc *arc,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
|
return Sta::sta()->arcDelayAnnotated(self, arc, dcalc_ap);
|
|
}
|
|
|
|
float
|
|
arc_delay(TimingArc *arc,
|
|
const Corner *corner,
|
|
const MinMax *min_max)
|
|
{
|
|
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
|
return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap));
|
|
}
|
|
|
|
const char *
|
|
cond()
|
|
{
|
|
FuncExpr *cond = self->timingArcSet()->cond();
|
|
if (cond)
|
|
return cond->asString();
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
const char *
|
|
mode_name()
|
|
{
|
|
return self->timingArcSet()->modeName();
|
|
}
|
|
|
|
const char *
|
|
mode_value()
|
|
{
|
|
return self->timingArcSet()->modeValue();
|
|
}
|
|
|
|
const char *
|
|
latch_d_to_q_en()
|
|
{
|
|
if (self->role() == TimingRole::latchDtoQ()) {
|
|
Sta *sta = Sta::sta();
|
|
const Network *network = sta->cmdNetwork();
|
|
const Graph *graph = sta->graph();
|
|
Pin *from_pin = self->from(graph)->pin();
|
|
Instance *inst = network->instance(from_pin);
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
TimingArcSet *d_q_set = self->timingArcSet();
|
|
LibertyPort *enable_port;
|
|
FuncExpr *enable_func;
|
|
RiseFall *enable_rf;
|
|
lib_cell->latchEnable(d_q_set, enable_port, enable_func, enable_rf);
|
|
const char *en_name = enable_port->name();
|
|
return stringPrintTmp("%s %s", en_name, enable_rf->asString());
|
|
|
|
}
|
|
return "";
|
|
}
|
|
|
|
} // Edge methods
|
|
|
|
%extend VertexIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Vertex *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
}
|
|
|
|
%extend VertexInEdgeIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Edge *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
}
|
|
|
|
%extend VertexOutEdgeIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Edge *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
}
|
|
|
|
%extend PathEnd {
|
|
bool is_unconstrained() { return self->isUnconstrained(); }
|
|
bool is_check() { return self->isCheck(); }
|
|
bool is_latch_check() { return self->isLatchCheck(); }
|
|
bool is_data_check() { return self->isDataCheck(); }
|
|
bool is_output_delay() { return self->isOutputDelay(); }
|
|
bool is_path_delay() { return self->isPathDelay(); }
|
|
bool is_gated_clock() { return self->isGatedClock(); }
|
|
Vertex *vertex() { return self->vertex(Sta::sta()); }
|
|
PathRef *path() { return &self->pathRef(); }
|
|
RiseFall *end_transition()
|
|
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
|
|
Slack slack() { return self->slack(Sta::sta()); }
|
|
ArcDelay margin() { return self->margin(Sta::sta()); }
|
|
Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); }
|
|
Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); }
|
|
TimingRole *check_role() { return self->checkRole(Sta::sta()); }
|
|
MinMax *min_max() { return const_cast<MinMax*>(self->minMax(Sta::sta())); }
|
|
float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); }
|
|
Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); }
|
|
Arrival source_clk_insertion_delay()
|
|
{ return self->sourceClkInsertionDelay(Sta::sta()); }
|
|
Clock *target_clk() { return self->targetClk(Sta::sta()); }
|
|
ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); }
|
|
Path *target_clk_path() { return self->targetClkPath(); }
|
|
float target_clk_time() { return self->targetClkTime(Sta::sta()); }
|
|
float target_clk_offset() { return self->targetClkOffset(Sta::sta()); }
|
|
float target_clk_mcp_adjustment()
|
|
{ return self->targetClkMcpAdjustment(Sta::sta()); }
|
|
Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); }
|
|
Arrival target_clk_insertion_delay()
|
|
{ return self->targetClkInsertionDelay(Sta::sta()); }
|
|
float target_clk_uncertainty()
|
|
{ return self->targetNonInterClkUncertainty(Sta::sta()); }
|
|
float inter_clk_uncertainty()
|
|
{ return self->interClkUncertainty(Sta::sta()); }
|
|
Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); }
|
|
bool path_delay_margin_is_external()
|
|
{ return self->pathDelayMarginIsExternal();}
|
|
Crpr common_clk_pessimism() { return self->commonClkPessimism(Sta::sta()); }
|
|
RiseFall *target_clk_end_trans()
|
|
{ return const_cast<RiseFall*>(self->targetClkEndTrans(Sta::sta())); }
|
|
|
|
}
|
|
|
|
%extend MinPulseWidthCheckSeqIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
MinPulseWidthCheck *next() { return self->next(); }
|
|
void finish() { delete self; }
|
|
} // MinPulseWidthCheckSeqIterator methods
|
|
|
|
%extend PathRef {
|
|
float
|
|
arrival()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return delayAsFloat(self->arrival(sta));
|
|
}
|
|
|
|
float
|
|
required()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return delayAsFloat(self->required(sta));
|
|
}
|
|
|
|
float
|
|
slack()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return delayAsFloat(self->slack(sta));
|
|
}
|
|
|
|
Pin *
|
|
pin()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return self->pin(sta);
|
|
}
|
|
|
|
const char *
|
|
tag()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
return self->tag(sta)->asString(sta);
|
|
}
|
|
|
|
// mea_opt3
|
|
TmpPinSeq *
|
|
pins()
|
|
{
|
|
Sta *sta = Sta::sta();
|
|
PinSeq *pins = new PinSeq;
|
|
PathRef path1(self);
|
|
while (!path1.isNull()) {
|
|
pins->push_back(path1.vertex(sta)->pin());
|
|
PathRef prev_path;
|
|
path1.prevPath(sta, prev_path);
|
|
path1.init(prev_path);
|
|
}
|
|
return pins;
|
|
}
|
|
|
|
}
|
|
|
|
%extend VertexPathIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
PathRef *
|
|
next()
|
|
{
|
|
Path *path = self->next();
|
|
return new PathRef(path);
|
|
}
|
|
|
|
void finish() { delete self; }
|
|
}
|
|
|
|
%extend SlowDrvrIterator {
|
|
bool has_next() { return self->hasNext(); }
|
|
Instance *next() { return self->next(); }
|
|
void
|
|
finish()
|
|
{
|
|
delete self->container();
|
|
delete self;
|
|
}
|
|
|
|
}
|
|
|
|
%extend Corner {
|
|
const char *name() { return self->name(); }
|
|
}
|
|
|
|
// Local Variables:
|
|
// mode:c++
|
|
// End:
|